When we write unit tests we usually try to apply our great object oriented knowledge, so we try to apply the well known DRY principle (Don't Repeat Yourself). One visible consequence of this effort is that the test code is considerably shorter than the previous version. A less visible consequence, but much more important, is that is harder to understand what the hell the test is trying to do.
For that reason, when writing tests, I'm more inclined to apply a non so well know principle called DAMP (Descriptive And Maintainable Procedures). When I write a test I try to think in myself in the future reading the test: will I be able to understand the test? Will I find the arrange phase of the test and understand what's happening there? Will I be able to understand easily why the test is failing (or passing)?
There are two main consequences of trying to apply DRY when writing a test. The first one is that we tend to write base classes where we put some kind of common code: variable initialization, mock setup (suitable for ALL tests), SUT creation... The second one is that we tend to write (with the help of the unit tests frameworks) setup methods with some common code too.
The result is that to be able to understand a test, I have to go up and down the file or, even worse, I have to go to a base class and see what's going on there.
There's no magic recipe to solve that. Some advice that may help you:
- Evaluate if your class under test is doing too many things.
- Don't use for/if/while in your test code (do more tests if necessary).
- Inline the test setup
- Use Test Data Builders to initialize your objects.
- When possible, mock everything that is not your class under test.