diff --git a/surefire-its/src/test/java/org/apache/maven/surefire/its/jiras/Surefire1787JUnit45IT.java b/surefire-its/src/test/java/org/apache/maven/surefire/its/jiras/Surefire1787JUnit45IT.java index 89b1398577..ce96fbe55a 100644 --- a/surefire-its/src/test/java/org/apache/maven/surefire/its/jiras/Surefire1787JUnit45IT.java +++ b/surefire-its/src/test/java/org/apache/maven/surefire/its/jiras/Surefire1787JUnit45IT.java @@ -143,7 +143,7 @@ public void junit5Suite() throws Exception { .verifyTextInLog("Running pkg.domain.AxTest") .assertThatLogLine(containsString("Running pkg.domain.BxTest"), equalTo(0)); - TestFile xmlReportFile = outputValidator.getSurefireReportsXmlFile("TEST-pkg.JUnit5Tests.xml"); + TestFile xmlReportFile = outputValidator.getSurefireReportsXmlFile("TEST-pkg.domain.AxTest.xml"); xmlReportFile.assertFileExists(); Source source = Input.fromFile(xmlReportFile.getFile()).build(); diff --git a/surefire-providers/surefire-junit-platform/src/main/java/org/apache/maven/surefire/junitplatform/RunListenerAdapter.java b/surefire-providers/surefire-junit-platform/src/main/java/org/apache/maven/surefire/junitplatform/RunListenerAdapter.java index 9c885e5013..455afbb2db 100644 --- a/surefire-providers/surefire-junit-platform/src/main/java/org/apache/maven/surefire/junitplatform/RunListenerAdapter.java +++ b/surefire-providers/surefire-junit-platform/src/main/java/org/apache/maven/surefire/junitplatform/RunListenerAdapter.java @@ -311,7 +311,29 @@ private TestIdentifier findTopParent(TestIdentifier testIdentifier) { // use deprecated method testPlan.getTestIdentifier( testIdentifier.getParentIdObject().get().toString()); - return !parent.getParentIdObject().isPresent() ? testIdentifier : findTopParent(parent); + if (!parent.getParentIdObject().isPresent()) { + return testIdentifier; + } + // Stop traversing at engine boundaries. When a test runs inside a Suite, + // the hierarchy contains a nested engine (e.g., junit-jupiter under junit-platform-suite). + // Without this check, tests would be incorrectly attributed to the Suite class + // instead of their actual test class. + if (isEngineIdentifier(parent)) { + return testIdentifier; + } + return findTopParent(parent); + } + + private static boolean isEngineIdentifier(TestIdentifier testIdentifier) { + String uniqueId = testIdentifier.getUniqueId(); + int lastOpen = uniqueId.lastIndexOf('['); + if (lastOpen >= 0) { + int colon = uniqueId.indexOf(':', lastOpen); + if (colon > lastOpen) { + return "engine".equals(uniqueId.substring(lastOpen + 1, colon)); + } + } + return false; } /** diff --git a/surefire-providers/surefire-junit-platform/src/test/java/org/apache/maven/surefire/junitplatform/RunListenerAdapterTest.java b/surefire-providers/surefire-junit-platform/src/test/java/org/apache/maven/surefire/junitplatform/RunListenerAdapterTest.java index 9e5c2fb354..115b8730c6 100644 --- a/surefire-providers/surefire-junit-platform/src/test/java/org/apache/maven/surefire/junitplatform/RunListenerAdapterTest.java +++ b/surefire-providers/surefire-junit-platform/src/test/java/org/apache/maven/surefire/junitplatform/RunListenerAdapterTest.java @@ -602,6 +602,62 @@ public void displayNamesIgnoredInReport() throws NoSuchMethodException { assertEquals("some display name", value.getNameText()); } + @Test + public void notifiedWithActualTestClassNameWhenRunInsideSuite() throws Exception { + // Build a Suite hierarchy: SuiteEngine -> SuiteClass -> JupiterEngine -> TestClass -> method + // This simulates @Suite @SelectPackages("...") running tests from another class. + EngineDescriptor suiteEngine = + new EngineDescriptor(UniqueId.forEngine("junit-platform-suite"), "JUnit Platform Suite"); + + TestDescriptor suiteClass = new ClassTestDescriptor( + suiteEngine.getUniqueId().append("suite", MySuiteClass.class.getName()), + MySuiteClass.class, + new DefaultJupiterConfiguration(CONFIG_PARAMS, OUTPUT_DIRECTORY)); + suiteEngine.addChild(suiteClass); + + TestDescriptor jupiterEngine = + new AbstractTestDescriptor( + suiteClass.getUniqueId().append("engine", "junit-jupiter"), "JUnit Jupiter") { + @Override + public Type getType() { + return Type.CONTAINER; + } + }; + suiteClass.addChild(jupiterEngine); + + TestDescriptor testClass = new ClassTestDescriptor( + jupiterEngine.getUniqueId().append("class", MyTestClass.class.getName()), + MyTestClass.class, + new DefaultJupiterConfiguration(CONFIG_PARAMS, OUTPUT_DIRECTORY)); + jupiterEngine.addChild(testClass); + + TestDescriptor method = new TestMethodTestDescriptor( + testClass.getUniqueId().append("method", MY_TEST_METHOD_NAME), + MyTestClass.class, + MyTestClass.class.getDeclaredMethod(MY_TEST_METHOD_NAME), + Collections::emptyList, + new DefaultJupiterConfiguration(CONFIG_PARAMS, OUTPUT_DIRECTORY)); + testClass.addChild(method); + + TestPlan plan = TestPlan.from(false, singletonList(suiteEngine), CONFIG_PARAMS, OUTPUT_DIRECTORY); + adapter.testPlanExecutionStarted(plan); + + adapter.executionStarted(TestIdentifier.from(suiteEngine)); + adapter.executionStarted(TestIdentifier.from(suiteClass)); + adapter.executionStarted(TestIdentifier.from(jupiterEngine)); + adapter.executionStarted(TestIdentifier.from(testClass)); + adapter.executionStarted(TestIdentifier.from(method)); + + ArgumentCaptor entryCaptor = ArgumentCaptor.forClass(ReportEntry.class); + adapter.executionFinished(TestIdentifier.from(method), failed(new AssertionError("fail"))); + verify(listener).testFailed(entryCaptor.capture()); + + ReportEntry entry = entryCaptor.getValue(); + // The source name must be the actual test class, not the Suite class + assertEquals(MyTestClass.class.getName(), entry.getSourceName()); + assertEquals(MY_TEST_METHOD_NAME, entry.getName()); + } + private static TestIdentifier newMethodIdentifier() throws Exception { return TestIdentifier.from(newMethodDescriptor()); } @@ -720,6 +776,8 @@ void myTestMethod(String foo) {} void myNamedTestMethod() {} } + private static class MySuiteClass {} + static class TestMethodTestDescriptorWithDisplayName extends AbstractTestDescriptor { private TestMethodTestDescriptorWithDisplayName( UniqueId uniqueId, Class testClass, Method testMethod, String displayName) {