Skip to content
This repository was archived by the owner on Feb 23, 2023. It is now read-only.

Commit 3dfeb77

Browse files
committed
Support "args" param in "@SpringBootTest"
Reflectively access `SpringBootTestArgs`(package private) to support `args` param in `@SpringBootTest`. Signed-off-by: Tadaya Tsuyukubo <tadaya@ttddyy.net>
1 parent e7fcd67 commit 3dfeb77

File tree

3 files changed

+47
-4
lines changed

3 files changed

+47
-4
lines changed

spring-native-configuration/src/main/java/org/springframework/boot/test/SpringBootTestHints.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,8 @@
6868
@TypeHint(types = org.springframework.web.context.ConfigurableWebApplicationContext.class, access = {}),
6969
@TypeHint(types = org.springframework.web.servlet.DispatcherServlet.class, access = {}),
7070
@TypeHint(types = org.springframework.web.reactive.DispatcherHandler.class, access = {}),
71-
@TypeHint(typeNames = "org.glassfish.jersey.server.ResourceConfig", access = {})
71+
@TypeHint(typeNames = "org.glassfish.jersey.server.ResourceConfig", access = {}),
72+
@TypeHint(typeNames = "org.springframework.boot.test.context.SpringBootTestArgs", access = {TypeAccess.DECLARED_METHODS})
7273
})
7374
public class SpringBootTestHints implements NativeConfiguration {
7475
}

spring-native/src/main/java/org/springframework/aot/test/boot/AotSpringBootConfigContextLoader.java

+29-3
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,11 @@
1616

1717
package org.springframework.aot.test.boot;
1818

19+
import java.lang.reflect.Method;
1920
import java.util.ArrayList;
2021
import java.util.Collections;
2122
import java.util.List;
23+
import java.util.Set;
2224

2325
import org.springframework.aot.SpringApplicationAotUtils;
2426
import org.springframework.boot.ApplicationContextFactory;
@@ -33,11 +35,15 @@
3335
import org.springframework.context.ApplicationContextInitializer;
3436
import org.springframework.context.ConfigurableApplicationContext;
3537
import org.springframework.core.env.ConfigurableEnvironment;
38+
import org.springframework.test.context.ContextCustomizer;
3639
import org.springframework.test.context.MergedContextConfiguration;
3740
import org.springframework.test.context.SmartContextLoader;
3841
import org.springframework.test.context.support.TestPropertySourceUtils;
3942
import org.springframework.test.context.web.WebMergedContextConfiguration;
43+
import org.springframework.util.Assert;
44+
import org.springframework.util.ClassUtils;
4045
import org.springframework.util.ObjectUtils;
46+
import org.springframework.util.ReflectionUtils;
4147
import org.springframework.web.context.support.GenericWebApplicationContext;
4248

4349
/**
@@ -49,6 +55,23 @@
4955
*/
5056
public class AotSpringBootConfigContextLoader extends SpringBootContextLoader {
5157

58+
// "SpringBootTestArgs#get(Set)" static method
59+
private static final Method SPRING_BOOT_TEST_ARGS__GET;
60+
61+
static {
62+
Class<?> clazz;
63+
try {
64+
// SpringBootTestArgs is a package private class
65+
clazz = ClassUtils.forName("org.springframework.boot.test.context.SpringBootTestArgs", null);
66+
} catch (ClassNotFoundException ex) {
67+
throw new IllegalStateException("Failed to load SpringBootTestArgs class", ex);
68+
}
69+
Method method = ReflectionUtils.findMethod(clazz, "get", Set.class);
70+
Assert.notNull(method, "SpringBootTestArgs#get(Set) method must exist");
71+
ReflectionUtils.makeAccessible(method);
72+
SPRING_BOOT_TEST_ARGS__GET = method;
73+
}
74+
5275
private final Class<? extends ApplicationContextInitializer<?>> testContextInitializer;
5376

5477
private final WebApplicationType webApplicationType;
@@ -80,9 +103,6 @@ public AotSpringBootConfigContextLoader(Class<? extends ApplicationContextInitia
80103

81104
@Override
82105
public ConfigurableApplicationContext loadContext(MergedContextConfiguration config) {
83-
// TODO: handle application arguments
84-
String[] args = new String[0];
85-
86106
SpringApplication application = new AotTestSpringApplication(config.getTestClass().getClassLoader(), testContextInitializer);
87107
application.setMainApplicationClass(config.getTestClass());
88108
application.setSources(Collections.singleton(testContextInitializer.getName()));
@@ -108,6 +128,8 @@ else if (this.webApplicationType == WebApplicationType.REACTIVE) {
108128
ApplicationContextFactory.of(GenericReactiveWebApplicationContext::new));
109129
}
110130
}
131+
132+
String[] args = resolveArguments(config.getContextCustomizers());
111133
ConfigurableApplicationContext context = application.run(args);
112134

113135
return context;
@@ -128,6 +150,10 @@ private void setActiveProfiles(ConfigurableEnvironment environment, String[] pro
128150
TestPropertyValues.of(pairs).applyTo(environment);
129151
}
130152

153+
private String[] resolveArguments(Set<ContextCustomizer> customizers) {
154+
return (String[]) ReflectionUtils.invokeMethod(SPRING_BOOT_TEST_ARGS__GET, null, customizers);
155+
}
156+
131157
private static class WebConfigurer {
132158

133159
void configure(MergedContextConfiguration configuration, SpringApplication application,

spring-native/src/test/java/org/springframework/aot/test/boot/AotSpringBootConfigContextLoaderTests.java

+16
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
import org.junit.jupiter.api.Test;
2323

2424
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
25+
import org.springframework.boot.ApplicationArguments;
2526
import org.springframework.boot.SpringBootConfiguration;
2627
import org.springframework.boot.WebApplicationType;
2728
import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest;
@@ -84,6 +85,16 @@ void loadContextSetActiveProfiles() {
8485
assertThat(context.getEnvironment().getActiveProfiles()).containsOnly("profile1", "profile2"));
8586
}
8687

88+
@Test
89+
void loadContextUseTestArguments() {
90+
AotSpringBootConfigContextLoader loader = new AotSpringBootConfigContextLoader(TestApplicationContextInitializer.class);
91+
run(() -> loader.loadContext(createMergedContextConfiguration(SampleArgumentsTest.class)), (context) -> {
92+
ApplicationArguments args = context.getBean(ApplicationArguments.class);
93+
assertThat(args.getOptionNames()).containsOnly("app.test");
94+
assertThat(args.getOptionValues("app.test")).containsOnly("one");
95+
});
96+
}
97+
8798
private void run(Supplier<ConfigurableApplicationContext> supplier, Consumer<AssertableApplicationContext> context) {
8899
try (ConfigurableApplicationContext ctx = supplier.get()) {
89100
context.accept(AssertableApplicationContext.get(() -> ctx));
@@ -108,6 +119,11 @@ static class SampleProfilesTest {
108119

109120
}
110121

122+
@SpringBootTest(args = "--app.test=one")
123+
static class SampleArgumentsTest {
124+
125+
}
126+
111127
@SpringBootConfiguration
112128
static class SampleConfiguration {
113129

0 commit comments

Comments
 (0)