Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Get name of currently executing test in JUnit 4

People also ask

How do you give a test name in JUnit?

JUnit @DisplayName annotation is used to provide a custom name for the test class and test methods. We can use spaces, special characters, and even emojis in the display name.

What is @rule in JUnit?

To use the JUnit rules, we need to add the @Rule annotation in the test. @Rule: It annotates the fields. It refer to the rules or methods that returns a rule. The annotated fields must be public, non-static, and subtypes of the TestRule or MethodRule. @Rule.

What is @before in junit5?

@BeforeEach is used to signal that the annotated method should be executed before each @Test method in the current test class.

What does @after do in JUnit?

org.junit Annotating a public void method with @After causes that method to be run after the Test method. All @After methods are guaranteed to run even if a Before or Test method throws an exception.


JUnit 4.7 added this feature it seems using TestName-Rule. Looks like this will get you the method name:

import org.junit.Rule;

public class NameRuleTest {
    @Rule public TestName name = new TestName();

    @Test public void testA() {
        assertEquals("testA", name.getMethodName());
    }

    @Test public void testB() {
        assertEquals("testB", name.getMethodName());
    }
}

JUnit 4.9.x and higher

Since JUnit 4.9, the TestWatchman class has been deprecated in favour of the TestWatcher class, which has invocation:

@Rule
public TestRule watcher = new TestWatcher() {
   protected void starting(Description description) {
      System.out.println("Starting test: " + description.getMethodName());
   }
};

Note: The containing class must be declared public.

JUnit 4.7.x - 4.8.x

The following approach will print method names for all tests in a class:

@Rule
public MethodRule watchman = new TestWatchman() {
   public void starting(FrameworkMethod method) {
      System.out.println("Starting test: " + method.getName());
   }
};

JUnit 5 and higher

In JUnit 5 you can inject TestInfo which simplifies test meta data providing to test methods. For example:

@Test
@DisplayName("This is my test")
@Tag("It is my tag")
void test1(TestInfo testInfo) {
    assertEquals("This is my test", testInfo.getDisplayName());
    assertTrue(testInfo.getTags().contains("It is my tag"));
}

See more: JUnit 5 User guide, TestInfo javadoc.


Try this instead:

public class MyTest {
        @Rule
        public TestName testName = new TestName();

        @Rule
        public TestWatcher testWatcher = new TestWatcher() {
            @Override
            protected void starting(final Description description) {
                String methodName = description.getMethodName();
                String className = description.getClassName();
                className = className.substring(className.lastIndexOf('.') + 1);
                System.err.println("Starting JUnit-test: " + className + " " + methodName);
            }
        };

        @Test
        public void testA() {
                assertEquals("testA", testName.getMethodName());
        }

        @Test
        public void testB() {
                assertEquals("testB", testName.getMethodName());
        }
}

The output looks like this:

Starting JUnit-test: MyTest testA
Starting JUnit-test: MyTest testB

NOTE: This DOES NOT work if your test is a subclass of TestCase! The test runs but the @Rule code just never runs.


Consider using SLF4J (Simple Logging Facade for Java) provides some neat improvements using parameterized messages. Combining SLF4J with JUnit 4 rule implementations can provide more efficient test class logging techniques.

import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.MethodRule;
import org.junit.rules.TestWatchman;
import org.junit.runners.model.FrameworkMethod;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class LoggingTest {

  @Rule public MethodRule watchman = new TestWatchman() {
    public void starting(FrameworkMethod method) {
      logger.info("{} being run...", method.getName());
    }
  };

  final Logger logger =
    LoggerFactory.getLogger(LoggingTest.class);

  @Test
  public void testA() {

  }

  @Test
  public void testB() {

  }
}

A convoluted way is to create your own Runner by subclassing org.junit.runners.BlockJUnit4ClassRunner.

You can then do something like this:

public class NameAwareRunner extends BlockJUnit4ClassRunner {

    public NameAwareRunner(Class<?> aClass) throws InitializationError {
        super(aClass);
    }

    @Override
    protected Statement methodBlock(FrameworkMethod frameworkMethod) {
        System.err.println(frameworkMethod.getName());
        return super.methodBlock(frameworkMethod);
    }
}

Then for each test class, you'll need to add a @RunWith(NameAwareRunner.class) annotation. Alternatively, you could put that annotation on a Test superclass if you don't want to remember it every time. This, of course, limits your selection of runners but that may be acceptable.

Also, it may take a little bit of kung fu to get the current test name out of the Runner and into your framework, but this at least gets you the name.


JUnit 4 does not have any out-of-the-box mechanism for a test case to get it’s own name (including during setup and teardown).