test && commit || revert - red tests

I’ve been spending the last few weeks playing with test && commit || revert, or TCR for short. When you write a test, you need to make sure that test is passing before you run your tests, or risk test failure (and code revert).

For example, here is a first test I might write while doing the Roman Numerals kata:

describe('roman numerals', () => {
  const tests = [
    { input: 'I', expected: 1 }
  ]

  tests.forEach(test => {
    const actual = arabic(test.input)
    const message = `should return ${test.expected} for input ${test.input}`
    it(message, () => assert.strictEqual(actual, test.expected))
  })
})

Before I run this test, I make sure I have an arabic function that returns 1:

function arabic() {
  return 1
}

This is already a bit different from TDD, insomuch that I don’t first see the test fail (in fact, I don’t think I want to see the test fail).

I then add another test for II:

  const tests = [
    ...
    { input: 'II', expected: 2 }
  ]

Before I run the test I update my implementation to ensure that it passes (remember, a failed test means that I have to reset to the last green commit):

function arabic(roman) {
  return roman.length
}

So far so good, but what happens when I add this test?

  const tests = [
    ...
    { input: 'V', expected: 5 },
  ]

I need to update my implementation to make the test pass, and I want the change to be simple enough to avoid a test failure. To accomplish that, I’ll add a guard clause to my implementation and hard-code the return value:

function arabic(roman) {
  if (roman === 'V') {
    return 5
  }
  return roman.length
}

I’ve found that I do this a lot when practicing TCR, I’ve been calling it “TCR expansion and contraction”. I add the guard clause that checks for a specific input value and returns a hard-coded result in order to get the test to pass and the code committed. Once I’ve got the code committed, I can add another test or start looking for a more general purpose solution, allowing me to ultimately remove the guard clause (contraction).

This is a good example of a small, safe change that is emblematic of TCR. Much like critiques of TDD, the act of adding a input-specific guard clause and hard-coded value seems silly – but the point is to try and safely iterate your way into a solution. I’m sure there are a numbers of ways to do that, and this is only one. It’s an interesting way to practice, if nothing else.

What do you think? Have you tried TCR? How are you handling the changes needed to make your new tests pass?