Writing simple tests is hard. Simple does not mean easy; it means straightforward and "not complex". The key to simple tests is not to add structure to your test code, but writing good production code.
A good programmer is a lazy programmer. So when we roll out our workshops, many participants start by taking control over the tests. They add builders, convenience and other productivity enhancers to the test suite. Once the test suite is theirs, they are free to pick up speed writing production code.
Or are they?
Don't add structure too soon
This behavior is a typical sign of a convergent programmer. Our divergence/convergence model is, again, not a good model, but a very useful model. It predicts what to expect and warns about pitfalls. The pitfall for a convergent programmer, in this context, is to add structure to the program before the domain is understood well enough. The result is a rigid test suite that does not allow for cheap refactoring.
Structure comes after learning
It's important to keep our solution model and code simple during the early phases of a new project or module. You are still getting familiar with the problem. The solution model and code should mainly serve to find information and knowledge about the problem. The solution will come; use your energy to evolve your problem model.
In practice this means that it's ok to copy and paste all over your tests. Keep the tests simple, even if they are a bit dirty. Once you have a better grasp of the problem, then it's time to add structure to the domain model. You will see that, as you extract meaningful, small objects from your domain code, the tests wil naturally become simpler as well. There will be little to no need for complex setup automation, because complex setup will be much less prevalent.
When you're done, your domain model should be neat and your tests simple and clean.
Don't add structure too late
Opposed from the convergent programmer, the divergent programmer tends to not clean up enough. There is little difference between the problem model and the solution model, and little deference to it: there is only code!
The issue with working code that somehow got to working, is that the understanding of the problem is not reflected in the solution. Lessons learned need to be incorporated before they are forgotten.
Imbue your lessons learned
Divergent programmers tend to move on before they have cleaned up their mess. As a result, they have quickly written some tests and production code, embracing the idea of "scaffolding" and drawing your tests up from production and vice versa. But when the "work" is done, the scaffolding should go. Take the time to extract meaningful objects, simplify and clean up tests, and remove dead code and tests.
When you're done, your domain model should be neat and your tests simple and clean.
Deliberate practice
The workshops Joop and I host are the result of internal workshops, where we deliberately train these skills. Both the convergent and divergent approach have their merit. The easiest way to produce the best results is not to do it all by yourself, but to work with someone who is not like you. Who is not like you to the degree that you are not like him or her; as convergent as you are divergent or the other way around. With a good understanding of each others strengths and enough deliberate practice, there is no simpler way to achieve more than each of you could achieve on your own.
Want help?
If you would like some help on how to achieve this, please follow Joop or me on Twitter. We do workshops regularly, with events once or twice a month, both in the Netherlands and abroad. If you want to host an event, then please let us know. We'd love to help you and your team shine.
Photo by Klemen Vrankar on Unsplash