Skip to content

Commit 8b3d5aa

Browse files
committed
Fix container failure XML reporting (#2542)
Prior to this commit, failing containers were only reported in case they contained at least one test. However, for example for a parameterized Jupiter tests and an exception in a `@BeforeAll` method, that led to failures being silently swallowed. Now, in addition to tests, leaf nodes of the test tree are always included in the XML report, even if they are containers, not tests. Moreover, failures on the container level that occurred after their children had been executed were not reported, e.g. when an exception was thrown from a Jupiter `@AfterAll` method. Now such failures cause the contained tests to be reported as failed. Fixes #2537.
1 parent b394ef0 commit 8b3d5aa

File tree

8 files changed

+220
-127
lines changed

8 files changed

+220
-127
lines changed

documentation/src/docs/asciidoc/release-notes/release-notes-5.7.1.adoc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ GitHub.
2727
of this change may be witnessed by end users and test engine or extension authors.
2828
* Method `scanForClassesInPackage(String)` in `ClasspathScanner` now returns a valid list
2929
of class names when the package name is equal to the name of a module on the module path.
30+
* The legacy XML report now always includes container-level failures (e.g. from
31+
`@BeforeAll` Jupiter lifecycle methods).
3032

3133
==== Deprecations and Breaking Changes
3234

junit-platform-engine/src/testFixtures/java/org/junit/platform/engine/support/hierarchical/DemoEngineExecutionContext.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,5 @@
1313
/**
1414
* @since 1.0
1515
*/
16-
class DemoEngineExecutionContext implements EngineExecutionContext {
16+
public class DemoEngineExecutionContext implements EngineExecutionContext {
1717
}

junit-platform-engine/src/testFixtures/java/org/junit/platform/engine/support/hierarchical/DemoHierarchicalTestDescriptor.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ public class DemoHierarchicalTestDescriptor extends AbstractTestDescriptor imple
2626
private String skippedReason;
2727
private boolean skipped;
2828

29-
DemoHierarchicalTestDescriptor(UniqueId uniqueId, String displayName, Runnable executeBlock) {
29+
public DemoHierarchicalTestDescriptor(UniqueId uniqueId, String displayName, Runnable executeBlock) {
3030
this(uniqueId, displayName, null, executeBlock);
3131
}
3232

junit-platform-engine/src/testFixtures/java/org/junit/platform/engine/support/hierarchical/DemoHierarchicalTestEngine.java

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
package org.junit.platform.engine.support.hierarchical;
1212

1313
import java.lang.reflect.Method;
14+
import java.util.function.Function;
1415

1516
import org.junit.platform.engine.EngineDiscoveryRequest;
1617
import org.junit.platform.engine.ExecutionRequest;
@@ -59,10 +60,8 @@ public DemoHierarchicalTestDescriptor addTest(Method testMethod, Runnable execut
5960
}
6061

6162
public DemoHierarchicalTestDescriptor addTest(String uniqueName, String displayName, Runnable executeBlock) {
62-
UniqueId uniqueId = engineDescriptor.getUniqueId().append("test", uniqueName);
63-
DemoHierarchicalTestDescriptor child = new DemoHierarchicalTestDescriptor(uniqueId, displayName, executeBlock);
64-
engineDescriptor.addChild(child);
65-
return child;
63+
return addChild(uniqueName, uniqueId -> new DemoHierarchicalTestDescriptor(uniqueId, displayName, executeBlock),
64+
"test");
6665
}
6766

6867
public DemoHierarchicalContainerDescriptor addContainer(String uniqueName, String displayName, TestSource source) {
@@ -76,11 +75,17 @@ public DemoHierarchicalContainerDescriptor addContainer(String uniqueName, Runna
7675
public DemoHierarchicalContainerDescriptor addContainer(String uniqueName, String displayName, TestSource source,
7776
Runnable beforeBlock) {
7877

79-
UniqueId uniqueId = engineDescriptor.getUniqueId().append("container", uniqueName);
80-
DemoHierarchicalContainerDescriptor container = new DemoHierarchicalContainerDescriptor(uniqueId, displayName,
81-
source, beforeBlock);
82-
engineDescriptor.addChild(container);
83-
return container;
78+
return addChild(uniqueName,
79+
uniqueId -> new DemoHierarchicalContainerDescriptor(uniqueId, displayName, source, beforeBlock),
80+
"container");
81+
}
82+
83+
public <T extends TestDescriptor & Node<DemoEngineExecutionContext>> T addChild(String uniqueName,
84+
Function<UniqueId, T> creator, String segmentType) {
85+
var uniqueId = engineDescriptor.getUniqueId().append(segmentType, uniqueName);
86+
var child = creator.apply(uniqueId);
87+
engineDescriptor.addChild(child);
88+
return child;
8489
}
8590

8691
@Override

junit-platform-reporting/src/main/java/org/junit/platform/reporting/legacy/xml/XmlReportData.java

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,16 @@
1111
package org.junit.platform.reporting.legacy.xml;
1212

1313
import static java.util.Collections.emptyList;
14+
import static java.util.stream.Collectors.toList;
1415
import static org.junit.platform.engine.TestExecutionResult.Status.ABORTED;
15-
import static org.junit.platform.engine.TestExecutionResult.Status.SUCCESSFUL;
1616

1717
import java.time.Clock;
1818
import java.time.Duration;
1919
import java.time.Instant;
2020
import java.util.ArrayList;
2121
import java.util.List;
2222
import java.util.Map;
23+
import java.util.Objects;
2324
import java.util.Optional;
2425
import java.util.concurrent.ConcurrentHashMap;
2526
import java.util.function.Predicate;
@@ -103,32 +104,23 @@ String getSkipReason(TestIdentifier testIdentifier) {
103104
}).orElse(null);
104105
}
105106

106-
Optional<TestExecutionResult> getResult(TestIdentifier testIdentifier) {
107-
if (this.finishedTests.containsKey(testIdentifier)) {
108-
return Optional.of(this.finishedTests.get(testIdentifier));
109-
}
110-
Optional<TestIdentifier> parent = this.testPlan.getParent(testIdentifier);
111-
Optional<TestIdentifier> ancestor = findAncestor(parent, this.finishedTests::containsKey);
112-
if (ancestor.isPresent()) {
113-
TestExecutionResult result = this.finishedTests.get(ancestor.get());
114-
if (result.getStatus() != SUCCESSFUL) {
115-
return Optional.of(result);
116-
}
117-
}
118-
return Optional.empty();
107+
List<TestExecutionResult> getResults(TestIdentifier testIdentifier) {
108+
return getAncestors(testIdentifier).stream() //
109+
.map(this.finishedTests::get) //
110+
.filter(Objects::nonNull) //
111+
.collect(toList());
119112
}
120113

121114
List<ReportEntry> getReportEntries(TestIdentifier testIdentifier) {
122115
return this.reportEntries.getOrDefault(testIdentifier, emptyList());
123116
}
124117

125118
private Optional<TestIdentifier> findSkippedAncestor(TestIdentifier testIdentifier) {
126-
return findAncestor(Optional.of(testIdentifier), this.skippedTests::containsKey);
119+
return findAncestor(testIdentifier, this.skippedTests::containsKey);
127120
}
128121

129-
private Optional<TestIdentifier> findAncestor(Optional<TestIdentifier> testIdentifier,
130-
Predicate<TestIdentifier> predicate) {
131-
Optional<TestIdentifier> current = testIdentifier;
122+
private Optional<TestIdentifier> findAncestor(TestIdentifier testIdentifier, Predicate<TestIdentifier> predicate) {
123+
Optional<TestIdentifier> current = Optional.of(testIdentifier);
132124
while (current.isPresent()) {
133125
if (predicate.test(current.get())) {
134126
return current;
@@ -138,4 +130,14 @@ private Optional<TestIdentifier> findAncestor(Optional<TestIdentifier> testIdent
138130
return Optional.empty();
139131
}
140132

133+
private List<TestIdentifier> getAncestors(TestIdentifier testIdentifier) {
134+
TestIdentifier current = testIdentifier;
135+
List<TestIdentifier> ancestors = new ArrayList<>();
136+
while (current != null) {
137+
ancestors.add(current);
138+
current = this.testPlan.getParent(current).orElse(null);
139+
}
140+
return ancestors;
141+
}
142+
141143
}

0 commit comments

Comments
 (0)