Testable Code – Is It Better Code?

designtddtestingunit testing

I'm attempting to get into the habit of writing unit tests regularly with my code, but I've read that first it's important to write testable code.
This question touches on SOLID principles of writing testable code, but I want to know if those design principles are beneficial (or at least not harmful) without planning on writing tests at all. To clarify – I understand the importance of writing tests; this is not a question on their usefulness.

To illustrate my confusion, in the piece that inspired this question, the writer gives an example of a function that checks the current time, and returns some value depending on the time. The author points to this as bad code because it produces the data (the time) it uses internally, thus making it difficult to test. To me, though, it seems like overkill to pass in the time as an argument. At some point the value needs to be initialized, and why not closest to consumption? Plus, the purpose of the method in my mind is to return some value based on the current time, by making it a parameter you imply that this purpose can/should be changed. This, and other questions, lead me to wonder if testable code was synonymous with "better" code.

Is writing testable code still good practice even in the absence of tests?


Is testable code actually more stable? has been suggested as a duplicate. However, that question is about the "stability" of the code, but I am asking more broadly about whether the code is superior for other reasons as well, such as readability, performance, coupling, and so forth.

Best Answer

In regard to the common definition of unit tests, I'd say no. I've seen simple code made convoluted because of the need to twist it to suit the testing framework (eg. interfaces and IoC everywhere making things difficult to follow through layers of interface calls and data that should be obvious passed in by magic). Given the choice between code that is easy to understand or code that is easy to unit test, I go with the maintainable code every time.

This doesn't mean not to test, but to fit the tools to suit you, not the other way round. There are other ways to test (but difficult-to-understand code is always bad code). For example, you can create unit tests that are less granular (eg. Martin Fowler's attitude that a unit is generally a class, not a method), or you can hit your program with automated integration tests instead. Such may not be as pretty as your testing framework lights up with green ticks, but we're after tested code, not the gamification of the process, right?

You can make your code easy to maintain and still be good for unit tests by defining good interfaces between them and then writing tests that exercise the public interface of the component; or you could get a better test framework (one that replaces functions at runtime to mock them, rather than requiring the code to be compiled with mocks in place). A better unit test framework lets you replace the system GetCurrentTime() functionality with your own, at runtime, so you don't need to introduce artificial wrappers to this just to suit the test tool.