The following is just a few thoughts from me, no facts or "the truth", so take what you think is valuable, and ignore the rest. :-)
When i encounter a new "methodology" my first question is "what problem does it try to tackle?".
While TDD focuses on commiting stable code, most people just remember the "red, green, refactor" rule. And yes thats kind of the heart of TDD. But quite a lot developers i encounter have big problems to make the cycle very small. That means to slice the increments into very small chunks.
As a result quite often they write a test, write productive code, the test still fails, the code is changed, and changed and changed, until the test is finally green.
That makes it very likely, that the resulting code contains elements that are not necessary, because they were left from a previous try. And now we can only hope that in the refactoring phase, those elements will be eliminated. As a result, the first refactoring phase has to focus on simple cleanups, instead of optimizing the design. And, quite often, after the simple cleanup, some devs think "i have done the refactoring, i am finished".
With not "allowing" productive code which results in a red test, this issue is kind of tackled. Now the procedure looks like this:
- My code is in a green state
- I am writing a new test (which may be faulty) => should result in a red flag
- I am writing production code (which also may be faulty)
- i run the tests and at least one fail.
- I analyze the issue (may be the new test was wrong, the new productive code did not fit the test, or the changes to the productive code broke existing tests)
- With the new knowledge, i reset my code and try again.
- Rinse and repeat, until all tests are green.
Personally i WANT in my version of TCR one red test result. After i wrote the test, before i started implementing the productive code. This red flag gives me the safe feeling, that my new test is not implemented with a "will always be green" mistake. So, this "red" i accept. But after i start implementing the productive code, "red" results (mostly, see later), result in a code reset.
When i want to follow this method, i have to learn to make my increments very small. Writing the test and the corresponding productive code for the next increment, may not take longer then just a few minutes. If it takes longer, the "reset" will erase a lot of work.
Following TDD is an API first approach (the API of the productive code that is used by the tests) and enforces deep thoughts about the code design. Following additionally TCR enforces the habit of having very small increments.
But perhaps some last words. TCR is a methodology, and like TDD it is not wise to follow it under all circumstances. If my test fails, because i made a spelling mistake, then i would correct that spelling mistake instead of reverting and just continue. The goal of TCR is to not patch code until it works, because the result will be very likely not be as clean as it could be. That means if my "patch" is extremely small and i can fully oversee it, then i would not reset my code.
Just remember, TCR will result in "having very small increments". And now think about an "exremely small patch"" in a "very small increment". That means we are really talking just about things the size of a spelling mistakes.
Kent Beck mentions this methodology in combination with "testing legacy code". That means the productive code already exists and we just now add tests to it.
In that scenario a new test should be green from the beginning. Again, personally i would try to ensure that the test is not faulty (beeing always green), therefore after the test runs green and i have commited the change, i would change the test in a way were it should fail. Please not by adding a "expect(1 === 2)" or something like that, but by changing the expected result slightly, like from
expect(result === "Hallo World") to
expect(result === "Hallo").
Also Kent Beck uses an automated reverting approach. Whenever a test fails, the code is reverted automatically. This is fine if you ONLY write tests (and do not change the productive code) AND your test is quite small, so that the error can ONLY be a wrong expectation (expecting a different result of the productive code). As soon as something else could be wrong. The test itself or the changed productive code, this approach will instantly delete the chance to analyze the issue. Therefore in those circumstances myself i would NOT use an automated approach.