Skip to content

Commit ea3e7df

Browse files
committed
Manually add @Ignore annotation to the JUnit38ClassRunner root description
1 parent 32a6465 commit ea3e7df

File tree

5 files changed

+58
-11
lines changed

5 files changed

+58
-11
lines changed

junit-vintage-engine/src/main/java/org/junit/vintage/engine/discovery/DefensiveAllDefaultPossibilitiesBuilder.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,12 @@ class DefensiveAllDefaultPossibilitiesBuilder extends AllDefaultPossibilitiesBui
5555
@Override
5656
public Runner runnerForClass(Class<?> testClass) throws Throwable {
5757
Runner runner = super.runnerForClass(testClass);
58-
if (testClass.getAnnotation(Ignore.class) != null) {
58+
Ignore ignoreAnnotation = testClass.getAnnotation(Ignore.class);
59+
if (ignoreAnnotation != null) {
5960
if (runner == null) {
6061
return new IgnoredClassRunner(testClass);
6162
}
62-
return decorateIgnoredTestClass(runner);
63+
return decorateIgnoredTestClass(runner, ignoreAnnotation);
6364
}
6465
return runner;
6566
}
@@ -72,11 +73,11 @@ public Runner runnerForClass(Class<?> testClass) throws Throwable {
7273
* override its runtime behavior (i.e. skip execution) but return its
7374
* regular {@link org.junit.runner.Description}.
7475
*/
75-
private Runner decorateIgnoredTestClass(Runner runner) {
76+
private Runner decorateIgnoredTestClass(Runner runner, Ignore ignoreAnnotation) {
7677
if (runner instanceof Filterable) {
77-
return new FilterableIgnoringRunnerDecorator(runner);
78+
return new FilterableIgnoringRunnerDecorator(runner, ignoreAnnotation);
7879
}
79-
return new IgnoringRunnerDecorator(runner);
80+
return new IgnoringRunnerDecorator(runner, ignoreAnnotation);
8081
}
8182

8283
@Override

junit-vintage-engine/src/main/java/org/junit/vintage/engine/discovery/FilterableIgnoringRunnerDecorator.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
package org.junit.vintage.engine.discovery;
1212

13+
import org.junit.Ignore;
1314
import org.junit.platform.commons.util.Preconditions;
1415
import org.junit.runner.Runner;
1516
import org.junit.runner.manipulation.Filter;
@@ -23,8 +24,8 @@
2324
*/
2425
class FilterableIgnoringRunnerDecorator extends IgnoringRunnerDecorator implements Filterable {
2526

26-
FilterableIgnoringRunnerDecorator(Runner runner) {
27-
super(runner);
27+
FilterableIgnoringRunnerDecorator(Runner runner, Ignore ignoreAnnotation) {
28+
super(runner, ignoreAnnotation);
2829
Preconditions.condition(runner instanceof Filterable,
2930
() -> "Runner must be an instance of Filterable: " + runner.getClass().getName());
3031
}

junit-vintage-engine/src/main/java/org/junit/vintage/engine/discovery/IgnoringRunnerDecorator.java

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,20 @@
1010

1111
package org.junit.vintage.engine.discovery;
1212

13+
import java.lang.annotation.Annotation;
14+
import java.util.ArrayList;
15+
import java.util.List;
16+
17+
import org.junit.Ignore;
18+
import org.junit.internal.runners.JUnit38ClassRunner;
19+
import org.junit.platform.commons.logging.Logger;
20+
import org.junit.platform.commons.logging.LoggerFactory;
1321
import org.junit.platform.commons.util.Preconditions;
1422
import org.junit.runner.Description;
1523
import org.junit.runner.Runner;
1624
import org.junit.runner.notification.RunNotifier;
1725
import org.junit.vintage.engine.descriptor.RunnerDecorator;
26+
import org.junit.vintage.engine.descriptor.RunnerTestDescriptor;
1827

1928
/**
2029
* Decorator for Runners that will be ignored completely.
@@ -26,15 +35,29 @@
2635
*/
2736
class IgnoringRunnerDecorator extends Runner implements RunnerDecorator {
2837

38+
private static final Logger logger = LoggerFactory.getLogger(RunnerTestDescriptor.class);
39+
2940
protected final Runner runner;
41+
private final Ignore testClassIgnoreAnnotation;
3042

31-
IgnoringRunnerDecorator(Runner runner) {
43+
IgnoringRunnerDecorator(Runner runner, Ignore ignoreAnnotation) {
3244
this.runner = Preconditions.notNull(runner, "Runner must not be null");
45+
this.testClassIgnoreAnnotation = Preconditions.notNull(ignoreAnnotation,
46+
"Test class @Ignore annotation must not be null");
3347
}
3448

3549
@Override
3650
public Description getDescription() {
37-
return runner.getDescription();
51+
Description originalDescription = runner.getDescription();
52+
53+
if (runner instanceof JUnit38ClassRunner) {
54+
return junit38ClassRunnerDescriptionWithIgnoreAnnotation(originalDescription);
55+
}
56+
else if (originalDescription.getAnnotation(Ignore.class) == null) {
57+
warnAboutMissingIgnoreAnnotation(originalDescription);
58+
}
59+
60+
return originalDescription;
3861
}
3962

4063
@Override
@@ -46,4 +69,26 @@ public void run(RunNotifier notifier) {
4669
public Runner getDecoratedRunner() {
4770
return runner;
4871
}
72+
73+
/**
74+
* {@link JUnit38ClassRunner} does not add class-level annotations to the runner description,
75+
* which results in an inconsistent behavior when combined with the vintage engine: the runner description
76+
* will be marked as started because the runner told so, but it will alos be reported as skipped by IgnoringRunnerDecorator
77+
* which detected the @Ignore annotation on the test Java class.
78+
*/
79+
private Description junit38ClassRunnerDescriptionWithIgnoreAnnotation(Description runnerDescription) {
80+
List<Annotation> effectiveAnnotations = new ArrayList<>(runnerDescription.getAnnotations());
81+
effectiveAnnotations.add(testClassIgnoreAnnotation);
82+
83+
Description updatedRunnerDescription = Description.createTestDescription(runnerDescription.getClassName(),
84+
runnerDescription.getMethodName(), effectiveAnnotations.toArray(new Annotation[0]));
85+
86+
runnerDescription.getChildren().forEach(updatedRunnerDescription::addChild);
87+
return updatedRunnerDescription;
88+
}
89+
90+
private void warnAboutMissingIgnoreAnnotation(Description originalDescription) {
91+
logger.warn(() -> "Custom test runner '" + runner.getClass().getName()
92+
+ "' did not add an @Ignore annotation to the runner description " + originalDescription);
93+
}
4994
}

junit-vintage-engine/src/test/java/org/junit/vintage/engine/VintageTestEngineExecutionTests.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -902,7 +902,7 @@ void executesIgnoredJUnit3TestCase() {
902902
var suiteClass = IgnoredJUnit3TestCase.class;
903903
execute(suiteClass).allEvents().assertEventsMatchExactly( //
904904
event(engine(), started()), //
905-
event(container(suiteClass), skippedWithReason(__ -> true)), //
905+
event(container(suiteClass), skippedWithReason("respected by Vintage engine")), //
906906
event(engine(), finishedSuccessfully()));
907907
}
908908

junit-vintage-engine/src/testFixtures/java/org/junit/vintage/engine/samples/junit3/IgnoredJUnit3TestCase.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
/**
1919
* @since 4.12
2020
*/
21-
@Ignore
21+
@Ignore("respected by Vintage engine")
2222
public class IgnoredJUnit3TestCase extends TestCase {
2323

2424
public void test() {

0 commit comments

Comments
 (0)