Writing tests that help evolve a system is hard, and you get there by avoiding smart tests while preferring dumb ones. Let's dive in.
The Paradox of Smart Tests 🤔Smart is always better than dumb, isn't it? Maybe, but maybe not. This time we'll look at the paradox that dumb programmer tests are superior to smart ones. This paradox demands an explanation, but first, we must consider what tests should be like.
Desired Qualities of Programmer Tests ☝️Well-written automated tests are:
- Easy to read
- Intention revealing
Anatomy of a Smart Test 🧬What is a smart test, then? Smart tests contain logic obscuring the true meaning of the test. For example, this logic might exist for one of these goals:
- capturing common setup
- creating test in- or output
- reducing the amount steps in the test
Superiority of Dumb Tests 🪄Dumb tests contain no magic and require no mental gymnastics to understand. They are easy to read and intention-revealing. Great tests might be DRY, but the best ones exhibit the DAMP (Descriptive and Meaningful Phrases) principle. Code always exists on a spectrum of being explicit and preventing duplication, and it is up to you to strike a good balance. Tests should value their ability to convey their meaning above all else. This is because a major goal of programmer tests is to explain production code, as I mentioned here. The last thing you want is to decipher the meaning of tests on top of understanding production code. There are strategies to get to tests that are both descriptive and easy to maintain, such as:
- The Test Data Builder Pattern, which allows you to construct test data in a better way.
- A thin, test-specific API around your production code that makes steps more expressive and course-grained.
- Employing Test-Driven Development, which encourages expressive tests from the inception of code.