Test lists
Let’s say we need to write some new functionality to an existing software. What should we do first? My observation is that most people familiar with test-driven development would say “Let’s start with a failing test!” The process is Red, Green, Refactor after all, right?
Sure, but before we start with the failing test, we have to know what to test. In his book Test Driven Development: By Example, Kent Beck introduces us to the concept of test list. Here’s an example from the book:
- $5 + 10 CHF = $10 if rate is 2:1
$5 * 2 = $10Make “amount” privateDollar side effects?- Money rounding?
equals()- hashCode()
- Equal null
- Equal object
The idea is that before you write any code, you spend a little bit of time thinking about what exactly you should be doing during the current programming session. You list down the tests and refactorings you can think of before you start any actual work.
I think the test list is a powerful tool that doesn’t get enough attention. I can think of at least two reasons for this from my personal experience. One reason is that people who teach test-driven development are typically a bit hyper-focused on the Red, Green, Refactor bit and forget the rest of the great advice and patterns in the book. The other reason might be that it reminds people of “too much up-front design”. It’s not up-front design though. It’s barely design at all. I think it’s the bare minimum of listing down the things you need to do next.
The biggest thing for me about the test list is that it unburdens my brain from having to keep many things in my head at the same time. A lot of the time we know exactly (or at least roughly) what to do next, but usually there are many different scenarios to consider for any given new functionality. Writing all these scenarios down means I don’t need to remember everything. I can focus more of my effort on actually solving the problem rather than remembering what kind of edge cases I have to consider next.
By jotting these things down, I also can examine what is the best place to start. Sometimes I think I know what test to write next, but after writing the test list I have decided to write another (simpler) case first. Sometimes it’s also not exactly obvious where to start. For example, some tests are easier to write in tiny baby steps, while others might require more steps and refactoring before you can straightforwardly write them. In these kinds of situations, I like having the test list. It makes the different options visible. It allows me to say “Well, I’ll try writing this test first. But if it turns out to be hard, I’ll try this other one first.”
The test list is extra valuable when you’re working collaboratively in a team or pairing. It helps ensure everybody present knows what needs to be done. It brings clarity. And if a new person joins the group during a programming session, I can just quickly show them the list and they will be able to tell what has been done recently, what’s we’re working on right now, and what’s still to be done.
It also tells you when you’re finished (when the list is empty). I’ve found that finishing all the items on the list gives you a sense of accomplishment. Sometimes—especially when working on something very abstract—it can be difficult to visualize the progress I’m making. The completed items on the list help give me a sense of progress that I might be missing otherwise.
The test list is not perfect. It does not have to include every single edge case you can think of. I think of it as a good place to start. While working, you will discover new tests to add or new refactorings to do. When that happens, you add them to the list. This way you can avoid getting distracted and focus on the task at hand. When you’re done with the current task, then you can look at the list again and see which test or refactoring would make sense next.
Next time before you start working on something new, try writing a test list. For me, it has brought much-needed clarity and structure to my daily coding activities. Your mileage may vary, but it’s a lightweight tool to try, so what do you have to lose?