TDD: Combining the when and then steps
I’ve written before about my favoured approach of writing tests in such a way that they have clear 'Given/When/Then' sections and something which I come across quite frequently is tests where the latter steps have been combined into one method call which takes care of both of these.
An example of this which I came across recently was roughly like this:
@Test
public void shouldCalculatePercentageDifferences() {
verifyPercentage(50, 100, 100);
verifyPercentage(100, 100, 0);
verifyPercentage(100, 50, -50);
}
private void verifyPercentage(int originalValue, int newValue, int expectedValue) {
assertEquals(expectedValue, new PercentageCalculator().calculatePercentage(originalValue, newValue));
}
This code is certainly adhering to the DRY principle although it took us quite a while to work out what the different numbers being passed into 'verifyPercentage' were supposed to represent.
With this type of test I think it makes more sense to have a bit of duplication to make it easier for us to understand the test.
We changed this test to have its assertions inline and make use of the Hamcrest library to do those assertions:
@Test
public void shouldCalculatePercentageDifferences() {
assertThat(new PercentageCalculator().calculatePercentage(50, 100), is(100));
assertThat(new PercentageCalculator().calculatePercentage(100, 100), is(0));
assertThat(new PercentageCalculator().calculatePercentage(100, 50), is(-50));
}
I think we may have also created a field to instantiate 'PercentageCalculator' so that we didn’t have to instantiate that three times.
Although we end up writing more code than in the first example I don’t think it’s a problem because it’s now easier to understand and we’ll be able to resolve any failures more quickly than we were able to previously.
As Michael Feathers points out during Jay Fields' 'Beta Test' presentation we need to remember why we try and adhere to the DRY principle in the first place.
To paraphrase his comments:
In production code if we don’t adhere to the DRY principle then we might make a change to a piece of code and we won’t know if there’s another place where we need to make a change as well. In test code the tests always tell us where we need to make changes because the tests will break.
About the author
I'm currently working on short form content at ClickHouse. I publish short 5 minute videos showing how to solve data problems on YouTube @LearnDataWithMark. I previously worked on graph analytics at Neo4j, where I also co-authored the O'Reilly Graph Algorithms Book with Amy Hodler.