Test Driven Development

Practical TDD

Let's talk about some of the nitty-gritty aspects of TDD.

QDT Question Driven Talk:

  • How can I write all my tests, when I don't even know all the implementation details?
  • What makes a good unit test?
  • How many tests should I have?
  • How should I order my tests?
  • How can I avoid code repetition within my tests?

TDD is the Socratic method, applied to coding!!!!

How can I write all my tests, when I don't even know all the implementation details?

A: Don't! Instead write them incrementally using the Fail-Pass-Refactor cycle.

TDD in a Nutshell

What makes a good unit test?

A: A good test should verify that one logical path through a method works.

Unit tests should be in 1-to-1 corresponondence with logical paths.

DO's:

  • Make sure every non-trivial method is tested
    • EG: get_account_status() →
      • test_get_account_status()
  • For every branch of logic within each method, create
    • EG: withdraw_cash() →
      • test_withdraw_test_normal()
      • test_withdraw_test_overdraft()
      • test_withdraw_test_disallowed()

DONT's:

  • No need to test trivial getters/setters
  • Don't stack all the logical pathways into a single long test for the method being tested. Instead, split them up as above

How many tests should I have?

The above answers the question, but make use of some helpful tools, such as code coverage.

How should I order my tests?

DON'T !!!!!

Every unit test should be completely independent of every other unit test. You'll have to build-up any necessary objects and context to make that specific unit testable.

How can I avoid code repetition within my tests?

You should use fixtures.

FIXTURES are a platform agnostic concept (so just because Django fixtures are "bad", doesn't mean you should dismiss the concept entirely. They refer to a part of the code that is in charge of building up the objects and context that are needed to run a test or a sequence of tests, and (possibly) also the code that cleans up after each test.

In practice in xUnit frameworks fixtures run mostly inside:

  • setUp()
  • tearDown()
  • setUpClass()
  • tearDownClass()