What to test?


I find test driven developement (TDD) to be a really effective way of coding through a problem. Getting started, however, can be difficult -- especially when the problem space is a bit fuzzy. What does one begin? What does one test? There are lots of resources out there for people looking to learn, but I'm going to take a stab at it for educational purposes. Here's hoping I'm not reinventing too many wheels. My main experiences with Test Driven Development come from working through The Odin Project, solving Ruby problems on Exorcism, and reading The Pragmatic Programmer.

  • limitations, caveats, expectations
    • I am attempting to be project, language, and framework agnostic.
    • This is a high level perspective.
  • kinds of tests to use
    1. unit tests (simple)
    2. integration testing (complex)
  1. unit test functions
    • testing pre-conditions, post-conditions
      • test at boundary conditions, within boundary conditions, and past boundary conditions
  2. Integration tests are less straight forward than unit tests because we are talking about testing interactions both within the code and with a user. I quite naturally use what the Pragmatic Programmer calls property-based testing to test code interacting with itself. This is a little less dogmatic and structured of a testing style because you are exploring your code base as you write these tests.
    • the idea behind property-based testing is to make assertions based on what your data looks like and how the code interacts with it.
    • you will begin to break your code up into:
      1. what must be true?
      2. what must not be changed?

In general, the idea is to test the interface not the implementation. This is the beauty behind the API architecture that seems to be current state of the web. There is something in this that almost points towards a unification of unit testing and integration testing -- perhaps a naive thought?

I have notes from a Sandi Metz talk I caught at some point where she simplified testing like this:

  1. three message origins: incoming, sent to self, outgoing
  2. two message types: query, command
  • incoming

    • query: test incoming query messages by making assertions about what they send back
    • command: test incoming command messages by making assertions about direct public side effects
    • if a message is both query and command; test those things seperately
    • receiver of incoming message has sole responsibility for asserting the result or direct public side effects
  • sent to self

    • aka private methods in ruby
    • redudant! can bind you to implementation if you try to test it explicitly
    • don't test them unless it saves $$$ during development; comment "if these tests fail delete them"
  • outgoing

    • query: don't test them! redudant and overspecification
    • command: Test outgoing command messages with expectations.