If I get stuck and I don’t know how a complex algorithm should work I’ll write a test for an error case. Then I’ll write a test for the simplest non-error case I can think of and return a hard coded value. Then I’ll write another test case and see if I can figure out the algorithm at that point. In doing so I gain some momentum and perhaps some insight in how the algorithm should behave on an edge case and a few normal cases.
This is called triangulation and it was used in celestial navigation for thousands of years. It is easier to see you are moving when you compare your position to two or more points on the horizon rather than just one. The same applies to coding; it is often easier to figure out the behavior of an algorithm by examining a couple of test cases instead of just one.
Triangulation is a valuable problem solving technique in TDD but it can also create its own problems. Once we figure out what we need from multiple tests they no longer serve any purpose and they become redundant tests. Redundant tests are tests that do not create any new distinctions.
If we recognize that redundancy in code is a maintenance issue then we should also see that redundancy in tests is also a maintenance issue. The purpose of QA is to try to break code to verify that it is robust. The purpose of TDD is to express the intent of code in as few tests as possible. Therefore, part of refactoring a system is removing redundant tests.