This is a question concerning the fundamental approach of TDD, so the example below is as simple as possible which might make it seem a little useless; but of course the question applies to more complicated situations as well.
Some colleagues and I are currently discussing and trying out some basic TDD ways of coding. We came across the questions how to deal with cheap solutions for existing but not encompassing TCs. In TDD one writes a TC which fails, then implements whatever it takes (and not more!) to let the TC pass. So the task at hand would be to make the TC green with as little effort as possible. If this means to implement a solution which uses inside knowledge of the TC, so be it. The reasoning was that later TCs would check for more general correctness anyway, so that first solution would need to be improved then (and only then).
Example:
We want to write a comparison function for a data structure with three fields. Our comparison shall return whether the given values are equal in all three fields (or differ in at least one). Our first written TC only checks if a difference in the two first values is detected properly: It passes (a,b,c)
and (a,b,c)
and checks for a correct detection of equality, then it passes (a,b,c)
and (x,b,c)
and checks for a correct detection of inequality.
Now the cheap approach would be to also implement only a comparison of the first field because this should be enough to pass this TC. Keep in mind that this can be done because we know that later tests will also check for the equality of the two other fields.
But of course it does not seem very useful to only implement such a (more or less) nonsense solution; every programmer doing this would do it in the knowledge of writing a bug. It obviously seems more natural to write a decent comparison right away in the first iteration.
On the other hand, writing a correct solution without having a TC which checks it might lead to the situation that such a TC which tests the behaviour more thoroughly will never get written. So there is behaviour which was written without having a TC for it (i. e. which is not developed test-driven).
Maybe a proper approach is to not write such rudimentary TCs (like the one only checking the first field) in the first place, but that would mean to demand perfect TCs in first iteration (and of course in complexer situations one will probably not always write perfect TCs).
So how should one deal with rudimentary TCs? Implement a cheap solution or not?