Unit Testing – Does Code Smell in Unit Tests Matter

code smellcode-qualityunit testing

Usually I just throw my unit tests together using copy and paste and all kind of other bad practices. The unit tests usually end up looking quite ugly, they're full of "code smell," but does this really matter? I always tell myself as long as the "real" code is "good" that's all that matters. Plus, unit testing usually requires various "smelly hacks" like stubbing functions.

How concerned should I be over poorly designed ("smelly") unit tests?

Best Answer

Are unit test smells important? Yes, definitely. However, they are different from code smells because unit tests serve a different purpose and have a different set of tensions that inform their design. Many smells in code don't apply to tests. Given my TDD mentality, I would actually argue that unit test smells are more important than code smells because the code is just there to satisfy the tests.

Here are some common unit testing smells:

  • Fragility: do your tests fail often and unexpectedly even for seemingly trivial or unrelated code changes?
  • State Leak: do your tests fail differently depending on, for instance, what order they are run?
  • Setup/Teardown Bloat: Are your setup/teardown blocks long and growing longer? Do they perform any sort of business logic?
  • Slow Runtime: Do your tests take a long time to run? Do any of your individual unit tests take longer than a tenth of a second to run? (Yes, I'm serious, a tenth of a second.)
  • Friction: Do existing tests make it difficult to write new tests? Do you find yourself struggling with test failures often while refactoring?

The importance of smells is that that they are useful indicators of design or other more fundamental issues, i.e. "where there's smoke, there's fire". Don't just look for test smells, look for their underlying cause as well.

Here, on the other hand, are some good practices for unit tests:

  • Fast, Focused Feedback: Your tests should isolate the failure quickly and give you useful information as to its cause.
  • Minimize Test-Code Distance: There should be a clear and short path between the test and the code that implements it. Long distances create unnecessarily long feedback loops.
  • Test One Thing At A Time: Unit tests should only test one thing. If you need to test another thing, write another test.
  • A Bug Is A Test You Forgot To Write: What can you learn from this failure to write better, more complete tests in the future?
Related Topic