Skip to content

Commit 4fe5e9e

Browse files
committed
Remove direct junit-platform-launcher dependency
Replace any direct `junit-platform-launcher` dependencies and instead rely on the test runner providing it. Launcher related class are not handled via reflection. This update allows us to workaround SUREFIRE-1679. Closes gh-17517
1 parent 543fcdb commit 4fe5e9e

File tree

13 files changed

+375
-53
lines changed

13 files changed

+375
-53
lines changed

spring-boot-project/spring-boot-test-autoconfigure/pom.xml

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -218,7 +218,6 @@
218218
<artifactId>spring-security-test</artifactId>
219219
<optional>true</optional>
220220
</dependency>
221-
222221
<!-- Test -->
223222
<dependency>
224223
<groupId>org.springframework.boot</groupId>
@@ -327,11 +326,6 @@
327326
</exclusion>
328327
</exclusions>
329328
</dependency>
330-
<dependency>
331-
<groupId>org.junit.platform</groupId>
332-
<artifactId>junit-platform-launcher</artifactId>
333-
<scope>test</scope>
334-
</dependency>
335329
<dependency>
336330
<groupId>org.mongodb</groupId>
337331
<artifactId>mongodb-driver-async</artifactId>

spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/cache/ImportsContextCustomizerFactoryWithAutoConfigurationTests.java

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -21,18 +21,16 @@
2121

2222
import org.junit.jupiter.api.Test;
2323
import org.junit.platform.engine.discovery.DiscoverySelectors;
24-
import org.junit.platform.launcher.Launcher;
25-
import org.junit.platform.launcher.LauncherDiscoveryRequest;
26-
import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder;
27-
import org.junit.platform.launcher.core.LauncherFactory;
28-
import org.junit.runners.model.InitializationError;
2924

3025
import org.springframework.beans.factory.annotation.Autowired;
3126
import org.springframework.boot.autoconfigure.AutoConfigurationPackage;
3227
import org.springframework.boot.autoconfigure.ImportAutoConfiguration;
3328
import org.springframework.boot.autoconfigure.domain.EntityScan;
3429
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
3530
import org.springframework.boot.test.autoconfigure.orm.jpa.ExampleEntity;
31+
import org.springframework.boot.testsupport.junit.platform.Launcher;
32+
import org.springframework.boot.testsupport.junit.platform.LauncherDiscoveryRequest;
33+
import org.springframework.boot.testsupport.junit.platform.LauncherDiscoveryRequestBuilder;
3634
import org.springframework.context.ApplicationContext;
3735
import org.springframework.context.annotation.Configuration;
3836
import org.springframework.test.context.ContextConfiguration;
@@ -51,7 +49,7 @@ class ImportsContextCustomizerFactoryWithAutoConfigurationTests {
5149
static ApplicationContext contextFromTest;
5250

5351
@Test
54-
void testClassesThatHaveSameAnnotationsShareAContext() throws InitializationError {
52+
void testClassesThatHaveSameAnnotationsShareAContext() throws Throwable {
5553
executeTests(DataJpaTest1.class);
5654
ApplicationContext test1Context = contextFromTest;
5755
executeTests(DataJpaTest3.class);
@@ -60,7 +58,7 @@ void testClassesThatHaveSameAnnotationsShareAContext() throws InitializationErro
6058
}
6159

6260
@Test
63-
void testClassesThatOnlyHaveDifferingUnrelatedAnnotationsShareAContext() throws InitializationError {
61+
void testClassesThatOnlyHaveDifferingUnrelatedAnnotationsShareAContext() throws Throwable {
6462
executeTests(DataJpaTest1.class);
6563
ApplicationContext test1Context = contextFromTest;
6664
executeTests(DataJpaTest2.class);
@@ -69,19 +67,19 @@ void testClassesThatOnlyHaveDifferingUnrelatedAnnotationsShareAContext() throws
6967
}
7068

7169
@Test
72-
void testClassesThatOnlyHaveDifferingPropertyMappedAnnotationAttributesDoNotShareAContext()
73-
throws InitializationError {
70+
void testClassesThatOnlyHaveDifferingPropertyMappedAnnotationAttributesDoNotShareAContext() throws Throwable {
7471
executeTests(DataJpaTest1.class);
7572
ApplicationContext test1Context = contextFromTest;
7673
executeTests(DataJpaTest4.class);
7774
ApplicationContext test2Context = contextFromTest;
7875
assertThat(test1Context).isNotSameAs(test2Context);
7976
}
8077

81-
private void executeTests(Class<?> testClass) {
82-
LauncherDiscoveryRequest request = LauncherDiscoveryRequestBuilder.request()
78+
private void executeTests(Class<?> testClass) throws Throwable {
79+
ClassLoader classLoader = testClass.getClassLoader();
80+
LauncherDiscoveryRequest request = new LauncherDiscoveryRequestBuilder(classLoader)
8381
.selectors(DiscoverySelectors.selectClass(testClass)).build();
84-
Launcher launcher = LauncherFactory.create();
82+
Launcher launcher = new Launcher(testClass.getClassLoader());
8583
launcher.execute(request);
8684
}
8785

spring-boot-project/spring-boot-test-autoconfigure/src/test/java/org/springframework/boot/test/autoconfigure/web/servlet/mockmvc/WebMvcTestPrintDefaultIntegrationTests.java

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,16 +19,15 @@
1919
import org.junit.jupiter.api.Test;
2020
import org.junit.jupiter.api.extension.ExtendWith;
2121
import org.junit.platform.engine.discovery.DiscoverySelectors;
22-
import org.junit.platform.launcher.Launcher;
23-
import org.junit.platform.launcher.LauncherDiscoveryRequest;
24-
import org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder;
25-
import org.junit.platform.launcher.core.LauncherFactory;
2622

2723
import org.springframework.beans.factory.annotation.Autowired;
2824
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
2925
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
3026
import org.springframework.boot.test.system.CapturedOutput;
3127
import org.springframework.boot.test.system.OutputCaptureExtension;
28+
import org.springframework.boot.testsupport.junit.platform.Launcher;
29+
import org.springframework.boot.testsupport.junit.platform.LauncherDiscoveryRequest;
30+
import org.springframework.boot.testsupport.junit.platform.LauncherDiscoveryRequestBuilder;
3231
import org.springframework.security.test.context.support.WithMockUser;
3332
import org.springframework.test.web.servlet.MockMvc;
3433

@@ -47,21 +46,22 @@
4746
class WebMvcTestPrintDefaultIntegrationTests {
4847

4948
@Test
50-
void shouldNotPrint(CapturedOutput output) {
49+
void shouldNotPrint(CapturedOutput output) throws Throwable {
5150
executeTests(ShouldNotPrint.class);
5251
assertThat(output).doesNotContain("HTTP Method");
5352
}
5453

5554
@Test
56-
void shouldPrint(CapturedOutput output) {
55+
void shouldPrint(CapturedOutput output) throws Throwable {
5756
executeTests(ShouldPrint.class);
5857
assertThat(output).contains("HTTP Method");
5958
}
6059

61-
private void executeTests(Class<?> testClass) {
62-
LauncherDiscoveryRequest request = LauncherDiscoveryRequestBuilder.request()
60+
private void executeTests(Class<?> testClass) throws Throwable {
61+
ClassLoader classLoader = testClass.getClassLoader();
62+
LauncherDiscoveryRequest request = new LauncherDiscoveryRequestBuilder(classLoader)
6363
.selectors(DiscoverySelectors.selectClass(testClass)).build();
64-
Launcher launcher = LauncherFactory.create();
64+
Launcher launcher = new Launcher(testClass.getClassLoader());
6565
launcher.execute(request);
6666
}
6767

spring-boot-project/spring-boot-tools/spring-boot-test-support/pom.xml

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -66,14 +66,6 @@
6666
<artifactId>jakarta.servlet-api</artifactId>
6767
<optional>true</optional>
6868
</dependency>
69-
<dependency>
70-
<groupId>org.junit.jupiter</groupId>
71-
<artifactId>junit-jupiter</artifactId>
72-
</dependency>
73-
<dependency>
74-
<groupId>org.junit.platform</groupId>
75-
<artifactId>junit-platform-launcher</artifactId>
76-
</dependency>
7769
<dependency>
7870
<groupId>org.mockito</groupId>
7971
<artifactId>mockito-core</artifactId>
@@ -130,6 +122,11 @@
130122
</exclusion>
131123
</exclusions>
132124
</dependency>
125+
<dependency>
126+
<groupId>org.junit.jupiter</groupId>
127+
<artifactId>junit-jupiter</artifactId>
128+
<scope>provided</scope>
129+
</dependency>
133130
<!-- Test -->
134131
<dependency>
135132
<groupId>org.hibernate.validator</groupId>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* Copyright 2012-2018 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.testsupport.junit.platform;
18+
19+
import java.lang.reflect.Array;
20+
21+
/**
22+
* Reflective mirror of JUnit 5's {@code Launcher}.
23+
*
24+
* @author Phillip Webb
25+
* @since 2.2.0
26+
*/
27+
public class Launcher extends ReflectiveWrapper {
28+
29+
private final Class<?> testExecutionListenerType;
30+
31+
private final Object instance;
32+
33+
public Launcher(ClassLoader classLoader) throws Throwable {
34+
super(classLoader, "org.junit.platform.launcher.Launcher");
35+
this.testExecutionListenerType = loadClass("org.junit.platform.launcher.TestExecutionListener");
36+
Class<?> factoryClass = loadClass("org.junit.platform.launcher.core.LauncherFactory");
37+
this.instance = factoryClass.getMethod("create").invoke(null);
38+
}
39+
40+
public TestPlan discover(LauncherDiscoveryRequest request) throws Throwable {
41+
return new TestPlan(getClassLoader(),
42+
this.type.getMethod("discover", request.type).invoke(this.instance, request.instance));
43+
}
44+
45+
public void registerTestExecutionListeners(SummaryGeneratingListener listener) throws Throwable {
46+
Object listeners = Array.newInstance(this.testExecutionListenerType, 1);
47+
Array.set(listeners, 0, listener.instance);
48+
this.type.getMethod("registerTestExecutionListeners", listeners.getClass()).invoke(this.instance, listeners);
49+
}
50+
51+
public void execute(LauncherDiscoveryRequest request) throws Throwable {
52+
Object listeners = Array.newInstance(this.testExecutionListenerType, 0);
53+
this.type.getMethod("execute", request.type, listeners.getClass()).invoke(this.instance, request.instance,
54+
listeners);
55+
}
56+
57+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
/*
2+
* Copyright 2012-2018 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.testsupport.junit.platform;
18+
19+
/**
20+
* Reflective mirror of JUnit 5's {@code LauncherDiscoveryRequest}.
21+
*
22+
* @author Phillip Webb
23+
* @since 2.2.0
24+
*/
25+
public class LauncherDiscoveryRequest extends ReflectiveWrapper {
26+
27+
final Object instance;
28+
29+
LauncherDiscoveryRequest(ClassLoader classLoader, Object instance) throws Throwable {
30+
super(classLoader, "org.junit.platform.launcher.LauncherDiscoveryRequest");
31+
this.instance = instance;
32+
}
33+
34+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
* Copyright 2012-2018 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.testsupport.junit.platform;
18+
19+
import java.lang.reflect.Method;
20+
21+
import org.junit.platform.engine.DiscoverySelector;
22+
23+
/**
24+
* Reflective mirror of JUnit 5's {@code LauncherDiscoveryRequestBuilder}.
25+
*
26+
* @author Phillip Webb
27+
* @since 2.2.0
28+
*/
29+
public class LauncherDiscoveryRequestBuilder extends ReflectiveWrapper {
30+
31+
final Object instance;
32+
33+
public LauncherDiscoveryRequestBuilder(ClassLoader classLoader) throws Throwable {
34+
super(classLoader, "org.junit.platform.launcher.core.LauncherDiscoveryRequestBuilder");
35+
this.instance = this.type.getMethod("request").invoke(null);
36+
}
37+
38+
LauncherDiscoveryRequestBuilder(ClassLoader classLoader, Class<?> type, Object instance) throws Throwable {
39+
super(classLoader, type);
40+
this.instance = instance;
41+
}
42+
43+
public LauncherDiscoveryRequestBuilder selectors(DiscoverySelector... selectors) throws Throwable {
44+
Class<?>[] parameterTypes = { DiscoverySelector[].class };
45+
Method method = this.type.getMethod("selectors", parameterTypes);
46+
return new LauncherDiscoveryRequestBuilder(getClassLoader(), this.type,
47+
method.invoke(this.instance, new Object[] { selectors }));
48+
}
49+
50+
public LauncherDiscoveryRequest build() throws Throwable {
51+
return new LauncherDiscoveryRequest(getClassLoader(), this.type.getMethod("build").invoke(this.instance));
52+
}
53+
54+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
* Copyright 2012-2018 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.testsupport.junit.platform;
18+
19+
import org.springframework.util.ClassUtils;
20+
21+
/**
22+
* Base class for all reflective wrappers.
23+
*
24+
* @author Phillip Webb
25+
*/
26+
class ReflectiveWrapper {
27+
28+
final ClassLoader classLoader;
29+
30+
final Class<?> type;
31+
32+
ReflectiveWrapper(ClassLoader classLoader, String type) throws Throwable {
33+
this.classLoader = classLoader;
34+
this.type = loadClass(type);
35+
}
36+
37+
protected ReflectiveWrapper(ClassLoader classLoader, Class<?> type) throws Throwable {
38+
this.classLoader = classLoader;
39+
this.type = type;
40+
}
41+
42+
protected final ClassLoader getClassLoader() {
43+
return this.classLoader;
44+
}
45+
46+
protected final Class<?> loadClass(String type) throws ClassNotFoundException, LinkageError {
47+
return ClassUtils.forName(type, this.classLoader);
48+
}
49+
50+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
* Copyright 2012-2018 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.testsupport.junit.platform;
18+
19+
/**
20+
* Reflective mirror of JUnit 5's {@code SummaryGeneratingListener}.
21+
*
22+
* @author Phillip Webb
23+
* @since 2.2.0
24+
*/
25+
public class SummaryGeneratingListener extends ReflectiveWrapper {
26+
27+
final Object instance;
28+
29+
public SummaryGeneratingListener(ClassLoader classLoader) throws Throwable {
30+
super(classLoader, "org.junit.platform.launcher.listeners.SummaryGeneratingListener");
31+
this.instance = this.type.newInstance();
32+
}
33+
34+
public TestExecutionSummary getSummary() throws Throwable {
35+
return new TestExecutionSummary(getClassLoader(), this.type.getMethod("getSummary").invoke(this.instance));
36+
}
37+
38+
}

0 commit comments

Comments
 (0)