Uncle Bob and Kent Beck agree on deleting redundant tests. For example, if you start by creating a stupid test requiring you to create a class which doesn’t exist yet, then the next test you write will test the existence of that class. They recommend the deletion of the first test because it’s redundant. As you test drive a more sophisticated solution, ultimately the say 10 tests you have are the result of perhaps 50 tests that became redundant with one another. Taking your
AddFraction example, I could say some tests are probably redundant. I’m on the fence though because I think they are all useful to document the code and also demonstrate that you’ve tested all necessary cases. Had you deleted any, the next developer looking at your test suite would not easily know if you’ve covered all cases. So what’s your thought on this guideline?
I don’t aggressively delete redundant tests. I err on the side of more tests, not fewer. I think this amounts to personal preference. I can’t justify it with any argument.
As you say, keeping the tests adds documentation, while removing the tests avoids wasteful inventory (in the Theory of Constraints sense). Even so, I sometimes remove tests and I also choose not to write tests if they seem redundant. I don’t have a clear set of rules that I follow here. It seems safe to write the tests unless you feel absolutely certain that you should delete them. Eventually, if you have this wrong, then you’ll regret deleting a test, and then you’ll act more cautiously. This becomes a self-regulating system.
I behave differently in training classes than I behave on an industrial-strength project. This affects what you see me do in my training videos compared to how I act in an everyday situation on a project. I recommend to Novice practitioners that they keep the tests. I recommend to Advanced Beginner practitioners that they keep the tests until those tests become “a problem” somehow. I do this because I believe that Novice practitioners benefit from writing and reading tests, so in most cases, more tests leads to better results. I also believe that Advanced Beginner practitioners benefit from starting to experiment with breaking “the rules” and exploring their own preferences and blind spots.
If you go back to the Point of Sale example, then after a while, I notice that the “product found” and the “another product found” tests become duplicates of each other, and I wonder whether I should delete one of them. In a training class, I encourage participants to keep them until they become “a problem” so that they will think about what it would mean for a test to become “a problem”. Programmers who practise TDD need to learn to judge when to remove a test because it has got in the way of some other, more urgent need, rather than dogmatically keep all the tests because “I wrote them, so I must still need them”. In this specific case, I appreciate the argument to remove the duplication (because I like removing duplication), but it creates another risk: we have no test anywhere that checks the case where there are many products in the store and the cashier scans the barcode of an existing product. You could imagine a programmer accidentally hardcoding the implementation
products.values.first in order to get something working, then forget to refactor this to
products.get(barcode), seeing the passing tests, and then moving on. This passes all our tests, but it doesn’t work. In this case, we’ve missed a test. For this reason, at worst, I would replace the “another product found” test with a test for “find a matching product among many products” test. (I don’t remember whether I put this in the Level 1 course. Probably not. I mention this in my live training classes as of 2017, if someone asks about it.)
I encourage you to always challenge any recommendation that doesn’t describe the recommender’s assumptions about the context. Any time you have the slightest doubt what the recommender is thinking, I advise you to ask, “When would you not follow this advice?” (See? I just did it!) Even if you think you know what the recommender is thinking, the question remains relevant and valuable. Of course, in a situation with a very low cost of failure, where you feel very confident that you already understanding, you might save that question for another day. (See? An example when I wouldn’t bother following the advice above. Easy.)