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.