Q:

Cheap implementations in fundamental TDD

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?

A:

I think your problem arises only because the requirement is very simple and the solution comparing all 3 values at once maybe just a one-liner. Having slightly more complex requirements, and it will perfectly make sense not to implement anything beyond the scope of the already implemented test cases.
Nevertheless, your "cheap approach" has indeed one advantage which makes it less nonsensical than you might think: chances are much better you don't forget to add all of the important test cases. If you implement the three-value comparison at once, there is a certain probability that you might omit further test cases, since you are already in the mental state of "beeing done". If, however, you know your code is "not ready" yet, and you force yourself not to change it without further test cases, chances are much higher you actually will take the time and add those test cases.
Especially for TDD learning purposes, I recommend "TDD as if you Meant it", an exercise invented by Keith Braithwaite to train developers doing TDD in even smaller steps. Applied to your example: in this exercise, your first step would not even be to implement a function with one equality check, you would implement the equality check in the testing code first, and then refactor it out afterwards to the comparison function.

