Unit Tests – How They Facilitate Design

designobject-oriented-designunit testing

Our colleague promotes writing unit tests as actually helping us to refine our design and refactor things, but I do not see how. If I am loading a CSV file and parse it, how is unit test (validating the values in the fields) gonna help me to verify my design? He mentioned coupling and modularity etc. but to me it does not make much sense – but I do not have much theoretical background, though.

That is not the same as the question you marked as duplicate, I would be interested in actual examples how this helps, not just theory saying "it helps". I like the answer below and the comment but I would like to learn more.

Best Answer

Not only do unit tests facilitate design, but that is one of their key benefits.

Writing test-first drives out modularity and clean code structure.

When you write your code test-first, you will find that any "conditions" of a given unit of code are naturally pushed out to dependencies (usually via mocks or stubs) when you assume them in your code.

"Given condition x, expect behaviour y," will often become a stub to supply x (which is a scenario in which the test needs to verify the behaviour of the current component) and y will become a mock, a call to which will be verified at the end of the test (unless it's a "should return y," in which case the test will just verify the return value explicitly).

Then, once this unit behaves as specified, you move on to writing the dependencies (for x and y) you have discovered.

This makes writing clean, modular code a very easy and natural process, where otherwise it's often easy to blur responsibilities and couple behaviours together without realising.

Writing tests later will tell you when your code is poorly structured.

When writing tests for a piece of code becomes difficult because there are too many things to stub or mock, or because things are too tightly coupled together, you know you have improvements to make in your code.

When "changing tests" becomes a burden because there are so many behaviours in a single unit, you know you have improvements to make in your code (or simply in your approach to writing tests - but this is not usually the case in my experience).

When your scenarios become too complicated ("if x and y and z then...") because you need to abstract more, you know you have improvements to make in your code.

When you end up with the same tests in two different fixtures because of duplication and redundancy, you know you have improvements to make in your code.

Here is an excellent talk by Michael Feathers demonstrating the very close relationship between testability and design in code (originally posted by displayName in the comments). The talk also addresses some common complaints and misconceptions about good design and testability in general.

Related Topic