Testability for me means unit testing. The ability to put a class in a test harness, simulate all of its possible inputs, and validate its outputs. To achieve this, the class must not be coupled to other classes. Coupling, in the sense that I mean it, would require you to test multiple classes simultaneously, rather than just the one. Often this leads to dependencies on things that can not be easily simulated in a test harness, like databases and hardware.
Testability also means simple tests. For tests to be simple, the class should have as few associations as possible. By associations I mean other classes with which the class under test must interact. Ideally these associated classes are substituted by mock or fake classes in the test harness. Each added association greatly increased test complexity.
For the tests to be simple the class itself should be simple. It may have highly complex logic, but it should be cohesive. That is, it should have a very limited set of responsibilities. If a class has one thing that it does, the programmer can readily ensure that the class does its one thing well. Cohesion simplifies testing because all the tests closely relate to one another. Closely related tests present opportunities for reuse in their setup and are thus easier to write.
All classes must have associations, however limited. Whenever possible these associations should be in the form of interfaces. Interfaces provide tremendous flexibility in design, and nowhere more so than in testing. Interfaces create the seams where test classes can be inserted in place of real ones, so that only the one class need be tested. One can readily instantiate the interfaces with fake or mock objects under test.
Of course testing classes with many associations is possible. It is now even possible to use aspect oriented programming techniques and frameworks like Typemock to test classes with all kinds of dependencies. I believe that designing for more traditional leads to better, more flexible design in general. In the ideal case software is designed for testability from the beginning. The next best case is refactoring existing code so that it can be tested. The least desirable scenario is using whatever means necessary to test existing code without changing it. In software, change is good. No software problem is ever solved optimally the first time. Software problems are rarely ever solved optimally.
Subscribe to:
Post Comments (Atom)
No comments:
Post a Comment