简体   繁体   中英

How to access an annotation value (JUnit 4 -> JUnit 5)

I am trying to port a project from JUnit 4 to JUnit 5. The project includes a custom runner that has a listener that detects whether a test has a certain annotation ( @GradedTest ) and accesses the annotation's key-value pairs. For example, it would be able to access the values associated with name and points in this code:

@Test
@GradedTest(name = "greet() test", points = "1")
public void defaultGreeting() {
    assertEquals(GREETING, unit.greet());
}

The existing JUnit 4 code has a listener that extends RunListener and overrides testStarted() :

@Override
public void testStarted(Description description) throws Exception {
    super.testStarted(description);

    this.currentGradedTestResult = null;

    GradedTest gradedTestAnnotation = description.getAnnotation(GradedTest.class);
    if (gradedTestAnnotation != null) {
        this.currentGradedTestResult =  new GradedTestResult(
                gradedTestAnnotation.name(),
                gradedTestAnnotation.number(),
                gradedTestAnnotation.points(),
                gradedTestAnnotation.visibility()
        );
    }
}

Note that this makes use of Description.getAnnotation() .

I am trying to switch to the JUnit Platform Launcher API . I can use a LauncherDiscoveryRequestBuilder to select the tests I want to run, and I can create listeners that extend SummaryGeneratingListener and override executionStarted(TestIdentifier testIdentifier) . I see no way, however, to get an annotation and its values from a TestIdentifier .

What is the JUnit 5 equivalent of Description.getAnnotation() or the new way of getting a test annotation's values?

I did find a way to get annotations, but I do not know how robust it is. This is how I overrode SummaryGeneratingListener.executionStarted(TestIdentifier identifier) :

@Override
public void executionStarted(TestIdentifier identifier) {
    super.executionStarted(identifier);
    this.currentGradedTestResult = null;

    // Check if this is an atomic test, not a container.
    if (identifier.isTest()) {
        // Check if the test's source is provided.
        TestSource source = identifier.getSource().orElse(null);
        // If so, and if it's a MethodSource, get and use the annotation if present.
        if (source != null && source instanceof MethodSource) {
            GradedTest gradedTestAnnotation = ((MethodSource) source).getJavaMethod().getAnnotation(GradedTest.class);
            if (gradedTestAnnotation != null) {
                this.currentGradedTestResult = new GradedTestResult(
                        gradedTestAnnotation.name(),
                        gradedTestAnnotation.number(),
                        gradedTestAnnotation.points(),
                        gradedTestAnnotation.visibility()
                );

                this.currentGradedTestResult.setScore(gradedTestAnnotation.points());
            }
        }
    }

    this.testOutput = new ByteArrayOutputStream();
    System.setOut(new PrintStream(this.testOutput));
}

The weak link is TestIdentifier.getSource() . The documentation says it gets "the source of the represented test or container, if available ." It works for my tests, but I don't know under what circumstances the source is (not) available.

I'm providing this as a solution but not marking this as answered, in case there's a better solution. If anyone is interested, there are the commits .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM