Unit Testing Tenets

Tres Seaver’s unit testing tenets.

Goals

Unit tests should:

  • be as simple as possible while still exercising the app under test.
  • run as quickly as possible to encourage running them frequently.
  • avoid couplings with other tests, or with parts of the codebase they are not responsible for testing.
  • be idempotent.

Tests should not:

  • replace narrative or API documentation.

Rules

  • Never import the module under test at test module scope.
  • Each test case method tests Just One Thing.
  • Test case names indicate what they test.
  • Don’t share test fixtures between test modules.

Guidelines

  • Minimize module-scope dependencies.
  • Do as little work as possible in the execution path of a single test.
  • Make fixtures as simple as possible.
  • Use globals judiciously.
  • Use stub/mock objects to clarify dependent contracts.

Conclusions

  • Tests are straightforward to write.
  • Excellent coverage.
  • Easy to debug/diagnose.
  • Quick to run.
  • Clarifies thinking about the code and its dependencies.

Demonstration

Let’s go back and improve the tests we wrote using Tres’ tenets.

What Do We Want To Fix

  • Bad test practices (importing things under-test at module scope).
  • Bad/missing stubs or mocks.
  • Bad fixtures.
  • Misuse of globals.

API Talk (Tangent)

  • Avoid Global State When Possible
  • Avoid Designing for Convenience (Don’t Give In To import Fascination)
  • Composition Usually Beats Inheritance
  • Avoid Using Others’ Code That Breaks These Rules