This has become my favorite subject because it turns out that testability, above nearly every other metrics, is important to strive for in developing software. All other code qualities seem to be a reflection of testability.
When I say testable code what I mean is code that can be verified programmatically and in a very granular way. When a test fails we wanted to tell us exactly why so that we know what went wrong and can correct the problem immediately. This means that we’re verifying very small units of behavior. This not only helps us debug code when there are problems it also helps keep us focused on building software that fulfills some desired behavior.
When we write our tests around behaviors rather than the way we implement those behaviors then we are free to change the implementations later, and if the behavior doesn’t change then our tests shouldn’t need to change either.
I know people who insist that every method must have a unit test. Well, I’m going to say a word here that I rarely say. That’s just WRONG. I don’t use that word often because there’s usually exceptions or contraindications that make something that’s wrong in one situation right in another. But this is not the case here. If you write too many tests or implementation tests when doing TDD then you’ll have issues when trying to refactor your code later.
Forget about code coverage for a second and think about testing behaviors. We don’t need to test private methods for example if they can be exercised through the public methods that call them.
I find that a key characteristic of testable code it is code that is focused on doing one thing that produces some kind of externally visible result. Unit tests should be simple and easily verifiable.
If the only way you can test the system is by programmatically acting like a user then you have essentially untestable code. System tests can be useful but they shouldn’t be your only strategy for testing. The days of printing call stacks in running the debugger are far less prominent thankfully because unit testing frameworks are far more valuable and durable. Testing is an investment and we want our investments to be valuable in the future.
Writing testable code means that the smallest components are independently verifiable. In order to do this, each component must have its dependencies injected into it. This means that code can’t reference global variables or use read/write singletons or service locators, etc. This may be a slightly different way of thinking about building a program than you’re used to but it can be a highly efficient and effective way of building software and it can be programmatically verified.
What are some benefits of testable code? Well, for one thing, it means that we can automate the verification process so we can keep our software in an always ready to release state. It also makes last-minute changes, the kind of changes that are often very important on a project, trivial and essentially cost-free. These are the same kind of changes that are often exorbitantly expensive to make late in a development project that doesn’t use automated regression testing.
Testable code is code of high quality. It’s cohesive and loosely coupled. It’s well encapsulated and in charge of its own state. In short, it’s singularly defined in its own proper place so that it’s straightforward to maintain and extend. Testability is one of my great teachers in revealing to me better options when I’m building software.
Note: This blog post is based on a section in my book, Beyond Legacy Code: Nine Practices to Extend the Life (and Value) of Your Software called Seven Strategies for Seven Strategies for Agile Infrastructure.
{2 Comments }
Previous Post: « Define Acceptance Criteria
Next Post: Keep Test Coverage Where it is Needed »
I have written a few tests. But not really tried TDD. How do I start?
Start by reading the blog posts on TDD on this blog and others. Read “Test-Driven Development by Example” by Kent Beck, and when you’re ready to really master test-first development and other essential developer practices, take one of my public classes or bring me in to teach your team. That’s the fast path to mastering these practices.