Generic Top

Get started with Spring 5 and Spring Boot 2, through the Learn Spring course:

>> CHECK OUT THE COURSE

1. Overview

When using JUnit, we may need our tests to have access to their name. This may help with error messages, especially for tests with system-generated names.

In this short tutorial, we'll look at how to get the name of the current test case in both JUnit 4 and JUnit 5.

2. JUnit 5 Approach

Let's look at two scenarios. First, we'll see how to get access to the name of a single test. This name is usually predictable since it's probably the name of the function or the value of the @DisplayName annotation. However, if we're using parameterized tests or display name generators, then we may need to know the name JUnit has provided.

JUnit 5 can inject a TestInfo object into our tests to show us the name of the current test case.

2.1. Individual Test

Let's inject a TestInfo object into our test function:

@Test
void givenNumbers_whenOddCheck_thenVerify(TestInfo testInfo) {
    System.out.println("displayName = " + testInfo.getDisplayName());
    int number = 5;
    assertTrue(oddCheck(number));
}

Here we have used the getDisplayName method of the interface TestInfo to display the name of the test. When we run the test, we get the test name:

displayName = givenNumbers_whenOddCheck_thenVerify(TestInfo)

2.2. Parameterized Test

Let's try this with a parameterized test. Here we'll use the name field of the @ParameterizedTest annotation to describe to JUnit how to produce a name for the test for us:

private TestInfo testInfo;

@BeforeEach
void init(TestInfo testInfo) {
    this.testInfo = testInfo;
}

@ParameterizedTest(name = "givenNumbers_whenOddCheck_thenVerify{0}")
@ValueSource(ints = { 1, 3, 5, -3, 15 })
void givenNumbers_whenOddCheck_thenVerify(int number) {
    System.out.println("displayName = " + testInfo.getDisplayName());
    assertTrue(oddCheck(number));
}

We should note that, unlike the individual test, we cannot inject TestInfo into the function. This is because the function parameters must relate to the parameterized data. To solve this we need to store the TestInfo in a field in the test class via the beforeEach method.

When we run the test, we get the test names:

displayName = givenNumbers_whenOddCheck_thenVerify5
displayName = givenNumbers_whenOddCheck_thenVerify-3
displayName = givenNumbers_whenOddCheck_thenVerify3
displayName = givenNumbers_whenOddCheck_thenVerify1
displayName = givenNumbers_whenOddCheck_thenVerify15

3. JUnit 4 Approach

JUnit 4 can populate a TestName object in our testsTestName is a JUnit rule, and rules are executed as part of JUnit's test execution, showing them the details of the currently running test along the way.

3.1. Individual Test

Let's consider an individual test:

@Rule
public TestName name = new TestName();

@Test
public void givenString_whenSort_thenVerifySortForString() {
    System.out.println("displayName = " + name.getMethodName());
    String s = "abc";
    assertEquals(s, sortCharacters("cba"));
}

As shown above, we can use the getMethodName method of class TestName to display the name of the test.

Let's run the test:

displayName = givenString_whenSort_thenVerifySortForString

3.2. Parameterized Test

Now let's use the same method to display the test name generated for a parameterized test. First, we need to annotate the test with the special test runner:

@RunWith(Parameterized.class)
public class JUnit4ParameterizedTestNameUnitTest {
}

Then we can implement the test with both the TestName rule and the fields and constructor for assigning the parameter values of the current test:

@Rule
public TestName name = new TestName();
private String input;
private String expected;

public JUnit4ParameterizedTestNameUnitTest(String input, String expected) {
    this.input = input;
    this.expected = expected;
}

@Parameterized.Parameters(name = "{0}")
public static Collection<Object[]> suppliedData() {
    return Arrays.asList(new Object[][] { 
      { "abc", "abc" }, { "cba", "abc" }, { "onm", "mno" }, { "a", "a" }, { "zyx", "xyz" }});
}

@Test
public void givenString_whenSort_thenVerifySortForString() {
    System.out.println("displayName = " + name.getMethodName());
    assertEquals(expected, sortCharacters(input));
}

In this test, we supply the test data Collection which contains both input strings as well as expected strings. This is done via the suppliedData function, annotated with the @Parameterized.Parameters annotation. This annotation also allows us to describe the test name.

When we run the test, the TestName rule is given the names of each test for us to see:

displayName = givenString_whenSort_thenVerifySortForString[abc]
displayName = givenString_whenSort_thenVerifySortForString[cba]
displayName = givenString_whenSort_thenVerifySortForString[onm]
displayName = givenString_whenSort_thenVerifySortForString[a]
displayName = givenString_whenSort_thenVerifySortForString[zyx]

4. Conclusion

In this article, we discussed how to find the name of the current test in both JUnit 4 and 5.

We saw how to do this for both individual tests and parameterized tests.

As usual, the complete source code is available over on GitHub.

Generic bottom

Get started with Spring 5 and Spring Boot 2, through the Learn Spring course:

>> CHECK OUT THE COURSE
Junit footer banner
Comments are closed on this article!