Unit testing done right – Better then sliced bread

Maybe the biggest thing since the rise of object oriented programming is test driven development. It’s also as hard to “get”. To help you on your journey, here some tips:

  • Have patience. Good unit testing need to be learned (like OOP, also see “TDD, What a bitch”). Use code-reviews of good unit-tests to learn good practices.
  • Again, have patience. Don’t skip unit-testing after some time. If you need to change tests often try to find the reason why and solve it. In many cases it’s actually a design issue (see next point). Everything falls with cleanly separated (and therefore testable) layers and DRY code. The need to reduce the dependencies for testing using mocks/stubs. “Duplicate code always represents a missing abstraction.” Robert C. Martin in Clean Code Tips
  • Group tests by the user-story they are testing. This ensures that you test the right thing and everything that belongs together is in one file. Use user-stories to define what feature is needed. Use BDD-Specs to describe the details of how a feature should behave. A test is simply a specification translated to code.
  • Tests should not depend on each other. Each test should be able to run correctly without any other test to be executed beforehand.
  • Tests need to be short (no scrolling). A better name for unit tests might be microtests. They just check one thing per test case. This helps to precisely identify where the bug is located (no need for debugging). It also helps to avoid brittle tests ( = tests that need to change often). If tests are too long, there is a good chance that the code under test has too many responsibilities and need to be split.
  • Run microtests as often as possible (best after each compile). Therefore make tests fast. Don’t test the database if avoidable. Don’t test more then one component at a time. More complicated, longer running tests (usually integration tests) can be run over night using an continuous integration server.
  • Microtests can be used to speed up implementation (“Need for speed”). They are a replacement for starting the whole system to check out whether the implementation works correctly. No monkey-testing no more!
  • While writing tests, think of everything that might get wrong (e.g. test whether code throws exception on invalid input, …). Many people tend check only whether the code behave well then it gets correct input. However code should always behave correctly (e.g. not crash) independent on the input it gets. This helps to write more robust code (again less debugging).
  • Write tests before writing the code. It helps to be more clear about the requirements and help to focus the programming efforts. In software development typing is never the bottleneck. Thinking is. Tests make development faster because they help to focus: “How TDD and Pairing Increase Production” and “They’re Called Microtests”
  • Let the tests drive the design of your API. Also see “Unit tests: An API design tool

More on this topic: