Get name of currently executing test in JUnit 4

2019-01-02 19:55发布

In JUnit 3, I could get the name of the currently running test like this:

public class MyTest extends TestCase
{
    public void testSomething()
    {
        System.out.println("Current test is " + getName());
        ...
    }
}

which would print "Current test is testSomething".

Is there any out-of-the-box or simple way to do this in JUnit 4?

Background: Obviously, I don't want to just print the name of the test. I want to load test-specific data that is stored in a resource with the same name as the test. You know, convention over configuration and all that.

13条回答
妖精总统
2楼-- · 2019-01-02 20:03
@ClassRule
public static TestRule watchman = new TestWatcher() {
    @Override
    protected void starting( final Description description ) {
        String mN = description.getMethodName();
        if ( mN == null ) {
            mN = "setUpBeforeClass..";
        }

        final String s = StringTools.toString( "starting..JUnit-Test: %s.%s", description.getClassName(), mN );
        System.err.println( s );
    }
};
查看更多
谁念西风独自凉
3楼-- · 2019-01-02 20:08

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).

查看更多
弹指情弦暗扣
4楼-- · 2019-01-02 20:16

In JUnit 5 there is TestInfo injection 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.

查看更多
不流泪的眼
5楼-- · 2019-01-02 20:18

In JUnit 5 TestInfo acts as a drop-in replacement for the TestName rule from JUnit 4.

From the documentation :

TestInfo is used to inject information about the current test or container into to @Test, @RepeatedTest, @ParameterizedTest, @TestFactory, @BeforeEach, @AfterEach, @BeforeAll, and @AfterAll methods.

To retrieve the method name of the current executed test, you have two options : String TestInfo.getDisplayName() and Method TestInfo.getTestMethod().

To retrieve only the name of the current test method TestInfo.getDisplayName() may not be enough as the test method default display name is methodName(TypeArg1, TypeArg2, ... TypeArg3).
Duplicating method names in @DisplayName("..") is not necessary a good idea.

As alternative you could use TestInfo.getTestMethod() that returns a Optional<Method> object.
If the retrieval method is used inside a test method, you don't even need to test the Optional wrapped value.

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.TestInfo;
import org.junit.jupiter.api.Test;

@Test
void doThat(TestInfo testInfo) throws Exception {
    Assertions.assertEquals("doThat(TestInfo)",testInfo.getDisplayName());
    Assertions.assertEquals("doThat",testInfo.getTestMethod().get().getName());
}
查看更多
初与友歌
6楼-- · 2019-01-02 20:20

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.

查看更多
临风纵饮
7楼-- · 2019-01-02 20:21

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() {

  }
}
查看更多
登录 后发表回答