Parameterise your Tests
Test cases usually include a number of repeated steps, especially in the process of creating data. This means that often test cases can become bloated in repetition, becoming cumbersome to find functionality failure points.
In many Java testing libraries, variable test parameters are a standard utility, and these should be used when appropriate (JUnit5 in this example).
The example below shows two small test cases, that given their functionality could be moved into a parameterised test case. Although the example is simple, it shows the complication that can come from multiple services interacting with each other.
class CalculatorServiceTest {
private final CalculatorService underTest = new CalculatorService();
@Test
void should_add_positive_numbers() {
long result = underTest.add(5, 5);
assertThat(result).isEqualTo(10);
}
@Test
void should_add_negative_numbers() {
long result = underTest.add(-5, -5);
assertThat(result).isEqualTo(-10);
}
@Test
void should_subtract_positive_numbers() {
long result = underTest.subtract(5, 5);
assertThat(result).isEqualTo(0);
}
@Test
void should_subtract_negative_numbers() {
long result = underTest.subtract(-5, -5);
assertThat(result).isEqualTo(0);
}
...
}
Refactoring
Now if we compare the above to the example below:
- It clearly states the intended changing parameters
- If any of the tests fail in future it will be clear to a future developer what the intended outcome of the original functionality was
- The pure content of the test is far smaller, meaning code reviews are likely to be faster
- Future test cases are easy to add
class CalculatorServiceTest {
private final CalculatorService underTest = new CalculatorService();
private static Stream<Arguments> addition_data() {
return Stream.of(
Arguments.of(5, 5, 10),
Arguments.of(-5, -5, -10),
Arguments.of(-5, 5, 0)
);
}
@ParameterizedTest
@MethodSource("addition_data")
void should_add_numbers_correctly(int number1, int number2, int expectedResult) {
long result = underTest.add(number1, number2);
assertThat(result).isEqualTo(expectedResult);
}
private static Stream<Arguments> subtraction_data() {
return Stream.of(
Arguments.of(5, 5, 0),
Arguments.of(5, -5, 10),
Arguments.of(-5, -5, 0)
);
}
@ParameterizedTest
@MethodSource("subtraction_data")
void should_subtract_numbers_correctly(int number1, int number2, int expectedResult) {
long result = underTest.subtract(number1, number2);
assertThat(result).isEqualTo(expectedResult);
}
}