10 Test code quality

 

This chapter covers

  • Principles and best practices of good and maintainable test code
  • Avoiding test smells that hinder the comprehension and evolution of test code

You have probably noticed that once test infected, the number of JUnit tests a software development team writes and maintains can become significant. In practice, test code bases grow quickly. Moreover, we have observed that Lehman’s law of evolution, “Code tends to rot, unless one actively works against it” (1980), also applies to test code. A 2018 literature review by Garousi and Küçük shows that our body of knowledge about things that can go wrong with test code is already comprehensive.

As with production code, we must put extra effort into writing high-quality test code bases so they can be maintained and developed sustainably. In this chapter, I discuss two opposite perspectives of writing test code. First, we examine what constitutes good and maintainable test code, and best practices that can help you keep complexity under control. Then we look at what constitutes problematic test code. We focus on key test smells that hinder test code comprehension and evolution.

I have discussed some of this material informally in previous chapters. This chapter consolidates that knowledge.

10.1 Principles of maintainable test code

10.1.1 Tests should be fast

10.1.2 Tests should be cohesive, independent, and isolated

10.1.3 Tests should have a reason to exist

10.1.4 Tests should be repeatable and not flaky

10.1.5 Tests should have strong assertions

10.1.6 Tests should break if the behavior changes

10.1.7 Tests should have a single and clear reason to fail

10.1.8 Tests should be easy to write

10.1.9 Tests should be easy to read

10.1.10 Tests should be easy to change and evolve

10.2 Test smells

10.2.1 Excessive duplication

10.2.2 Unclear assertions

10.2.3 Bad handling of complex or external resources