One test at a time, one step at a time
Updated: 4 days ago
My favourite way to create something big that works, is to start with something small that works. Test Driven Development has the benefit of resulting in automated regression tests, but that is not why I like it the most. According to Theory of Constraints starting with verification reduces waste. To me the tests are a sounding board in the thinking process of creating software. So I write one test at the time, and here is why:
In the red-green-refactor cycle, when a test is red, that was expected to turn green, we need feedback. When the code is not doing what we think it should, one red test has a lot more information than ten. With only one red test at the time, we can be sure that it is the latest change we did that is not working. If writing trivial code this will never happen. But not all code is trivial, and some code get less trivial just before lunch or during a bad day.
Code that is designed to be tested is also designed to be reused, since tests are also code using your units. When figuring out how to do this, the API of the unit might change. With great refactoring tools changing multiple tests are quickly done. But still, having to repair something, that has not brought value yet, is wasteful.
Just the right amount of tests
It can be hard to know how many tests that is enough, before you start implementing them. A downside of tests is that they are code that have to be maintained, and take time to run. So not having too many tests is really valuable. If the first step is to invent all tests that might be useful, our inventive power might make us a bit too productive, creating tests that will end up being waste. One effect of red-green-refactor is that no tests can be written for code that is already implementing the functionality tested, since you need to start with a test that is red. That prevents us from writing duplicate tests.
As a backlog contains stories to implement later, a test file can contain a list of test descriptions, names, or corner cases. That can be our outer loop. For the inner loop I want red-green-refactor, for one test at a time, one step at the time.
ps. If the code got too clever too early and you think that you might not have full test coverage — there is a solution. To make sure that everything the code does is covered with tests, mutation testing can be used. Mutation testing is when you change the code to test if it is covered by a test. A "mutant" is introduced by changing a constant, swapping a conditional or something else that should modify the functionality of the code. When a mutant is introduced and no tests go red, you can write a new one that does fail. That test is then red, and when the code is restored, it turns green. That way there will be only the tests needed, and hopefully all the tests needed.