Add SpringBootTest.useMainMethod support
Add a new `useMainMethod` attribute to `SpringBootTest` which can be used to determine how the test should run. The three available options are: - `ALWAYS` - `NEVER` - `WHEN_AVAILABLE` The default is `WHEN_AVAILABLE` which will attempt to launch the test using the `main` method if there is one. The `SpringBootContextLoader` has been updated to use the new `SpringApplicationHook` interface when the main method is being used. Closes gh-22405
This commit is contained in:
@@ -137,6 +137,44 @@ Therefore, as long as your tests share the same configuration (no matter how it
|
||||
|
||||
|
||||
|
||||
[[features.testing.spring-boot-applications.using-main]]
|
||||
==== Using the Test Configuration Main Method
|
||||
Typically the test configuration discovered by `@SpringBootTest` will be your main `@SpringBootApplication`.
|
||||
In most well structured applications, this configuration class will also include the `main` method used to launch the application.
|
||||
|
||||
For example, the following is a very common code pattern for a typical Spring Boot application:
|
||||
|
||||
include::code:typical/MyApplication[]
|
||||
|
||||
In the example above, the `main` method doesn't do anything other than delegate to `SpringApplication.run`.
|
||||
It is, however, possible to have a more complex `main` method that applies customizations before calling `SpringApplication.run`.
|
||||
|
||||
For example, here is an application that changes the banner mode and sets additional profiles:
|
||||
|
||||
include::code:custom/MyApplication[]
|
||||
|
||||
Since customizations in the `main` method can affect the resulting `ApplicationContext`, Spring Boot will also attempt to use the `main` method for tests.
|
||||
By default, `@SpringBootTest` will detect any `main` method on your `@SpringBootConfiguration` and run it up to the point that the `SpringApplication.run` method is called.
|
||||
If your `@SpringBootConfiguration` class doesn't have a main method, the class itself is used directly to create the `ApplicationContext`.
|
||||
|
||||
In some situations, you may find that you can't or don't want to run the `main` method in your tests.
|
||||
If that's the case, you can change the `useMainMethod` attribute of `@SpringBootTest` to `UseMainMethod.NEVER`.
|
||||
|
||||
For example, you might have the following application class:
|
||||
|
||||
include::code:never/MyApplication[]
|
||||
|
||||
If a test wants to use the `MyApplication` configuration without calling the main method, it can be written as follows:
|
||||
|
||||
include::code:never/MyApplicationTests[]
|
||||
|
||||
The test above will still use `MyApplication` to create the `ApplicationContext`, however, it won't call `MyCode.expensiveOperation()` since the `main` method is not invoked.
|
||||
|
||||
If you want to do the opposite, and ensure that the `main` method is always invoked, you can set the `useMainMethod` attribute of `@SpringBootTest` to `UseMainMethod.ALWAYS`.
|
||||
If this property is set, and no `main` method can be found the test will fail.
|
||||
|
||||
|
||||
|
||||
[[features.testing.spring-boot-applications.excluding-configuration]]
|
||||
==== Excluding Test Configuration
|
||||
If your application uses component scanning (for example, if you use `@SpringBootApplication` or `@ComponentScan`), you may find top-level configuration classes that you created only for specific tests accidentally get picked up everywhere.
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright 2012-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.docs.features.testing.springbootapplications.usingmain.custom;
|
||||
|
||||
import org.springframework.boot.Banner;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class MyApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication application = new SpringApplication(MyApplication.class);
|
||||
application.setBannerMode(Banner.Mode.OFF);
|
||||
application.setAdditionalProfiles("myprofile");
|
||||
application.run(args);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright 2012-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.docs.features.testing.springbootapplications.usingmain.never;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class MyApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
MyCode.expensiveOperation();
|
||||
SpringApplication.run(MyApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2012-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.docs.features.testing.springbootapplications.usingmain.never;
|
||||
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.UseMainMethod;
|
||||
|
||||
@SpringBootTest(useMainMethod = UseMainMethod.NEVER)
|
||||
public class MyApplicationTests {
|
||||
|
||||
@Test
|
||||
void exampleTest() {
|
||||
// ...
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* Copyright 2012-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.docs.features.testing.springbootapplications.usingmain.never;
|
||||
|
||||
public final class MyCode {
|
||||
|
||||
private MyCode() {
|
||||
}
|
||||
|
||||
static void expensiveOperation() {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2012-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.docs.features.testing.springbootapplications.usingmain.typical;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
@SpringBootApplication
|
||||
public class MyApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(MyApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2012-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.docs.features.testing.springbootapplications.usingmain.custom
|
||||
|
||||
import org.springframework.boot.Banner
|
||||
import org.springframework.boot.runApplication
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication
|
||||
|
||||
@SpringBootApplication
|
||||
class MyApplication
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
runApplication<MyApplication>(*args) {
|
||||
setBannerMode(Banner.Mode.OFF)
|
||||
setAdditionalProfiles("myprofile");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2012-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.docs.features.testing.springbootapplications.usingmain.custom.never
|
||||
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication
|
||||
import org.springframework.boot.docs.using.structuringyourcode.locatingthemainclass.MyApplication
|
||||
import org.springframework.boot.runApplication
|
||||
|
||||
@SpringBootApplication
|
||||
class MyApplication
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
MyCode.expensiveOperation()
|
||||
runApplication<MyApplication>(*args)
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright 2012-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.docs.features.testing.springbootapplications.usingmain.custom.never
|
||||
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.springframework.boot.test.context.SpringBootTest
|
||||
import org.springframework.boot.test.context.SpringBootTest.UseMainMethod
|
||||
import org.springframework.context.annotation.Import
|
||||
|
||||
@SpringBootTest(useMainMethod = UseMainMethod.NEVER)
|
||||
class MyApplicationTests {
|
||||
|
||||
@Test
|
||||
fun exampleTest() {
|
||||
// ...
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* Copyright 2012-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.docs.features.testing.springbootapplications.usingmain.custom.never
|
||||
|
||||
class MyCode {
|
||||
companion object {
|
||||
fun expensiveOperation() {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2012-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.docs.features.testing.springbootapplications.usingmain.typical
|
||||
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication
|
||||
import org.springframework.boot.docs.using.structuringyourcode.locatingthemainclass.MyApplication
|
||||
import org.springframework.boot.runApplication
|
||||
|
||||
@SpringBootApplication
|
||||
class MyApplication
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
runApplication<MyApplication>(*args)
|
||||
}
|
||||
@@ -16,16 +16,23 @@
|
||||
|
||||
package org.springframework.boot.test.context;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.BeanUtils;
|
||||
import org.springframework.boot.ApplicationContextFactory;
|
||||
import org.springframework.boot.ConfigurableBootstrapContext;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.SpringApplication.AbandonedRunException;
|
||||
import org.springframework.boot.SpringApplicationHook;
|
||||
import org.springframework.boot.SpringApplicationRunListener;
|
||||
import org.springframework.boot.SpringBootConfiguration;
|
||||
import org.springframework.boot.WebApplicationType;
|
||||
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.boot.test.context.SpringBootTest.UseMainMethod;
|
||||
import org.springframework.boot.test.mock.web.SpringBootMockServletContext;
|
||||
import org.springframework.boot.test.util.TestPropertyValues;
|
||||
import org.springframework.boot.test.util.TestPropertyValues.Type;
|
||||
@@ -54,7 +61,9 @@ import org.springframework.test.context.support.TestPropertySourceUtils;
|
||||
import org.springframework.test.context.web.WebMergedContextConfiguration;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.function.ThrowingSupplier;
|
||||
import org.springframework.web.context.ConfigurableWebApplicationContext;
|
||||
import org.springframework.web.context.support.GenericWebApplicationContext;
|
||||
|
||||
@@ -86,7 +95,47 @@ public class SpringBootContextLoader extends AbstractContextLoader {
|
||||
@Override
|
||||
public ApplicationContext loadContext(MergedContextConfiguration mergedConfig) throws Exception {
|
||||
assertHasClassesOrLocations(mergedConfig);
|
||||
SpringBootTestAnnotation annotation = SpringBootTestAnnotation.get(mergedConfig);
|
||||
String[] args = annotation.getArgs();
|
||||
UseMainMethod useMainMethod = annotation.getUseMainMethod();
|
||||
ContextLoaderHook hook = new ContextLoaderHook(mergedConfig);
|
||||
if (useMainMethod != UseMainMethod.NEVER) {
|
||||
Method mainMethod = getMainMethod(mergedConfig, useMainMethod);
|
||||
if (mainMethod != null) {
|
||||
return hook.run(() -> ReflectionUtils.invokeMethod(mainMethod, null, new Object[] { args }));
|
||||
}
|
||||
}
|
||||
SpringApplication application = getSpringApplication();
|
||||
return hook.run(() -> application.run(args));
|
||||
}
|
||||
|
||||
private void assertHasClassesOrLocations(MergedContextConfiguration mergedConfig) {
|
||||
boolean hasClasses = !ObjectUtils.isEmpty(mergedConfig.getClasses());
|
||||
boolean hasLocations = !ObjectUtils.isEmpty(mergedConfig.getLocations());
|
||||
Assert.state(hasClasses || hasLocations,
|
||||
() -> "No configuration classes or locations found in @SpringApplicationConfiguration. "
|
||||
+ "For default configuration detection to work you need Spring 4.0.3 or better (found "
|
||||
+ SpringVersion.getVersion() + ").");
|
||||
}
|
||||
|
||||
private Method getMainMethod(MergedContextConfiguration mergedConfig, UseMainMethod useMainMethod) {
|
||||
Class<?> springBootConfiguration = Arrays.stream(mergedConfig.getClasses())
|
||||
.filter(this::isSpringBootConfiguration).findFirst().orElse(null);
|
||||
Assert.state(springBootConfiguration != null || useMainMethod == UseMainMethod.WHEN_AVAILABLE,
|
||||
"Cannot use main method as no @SpringBootConfiguration-annotated class is available");
|
||||
Method mainMethod = (springBootConfiguration != null)
|
||||
? ReflectionUtils.findMethod(springBootConfiguration, "main", String[].class) : null;
|
||||
Assert.state(mainMethod != null || useMainMethod == UseMainMethod.WHEN_AVAILABLE,
|
||||
() -> "Main method not found on '%s'".formatted(springBootConfiguration.getName()));
|
||||
return mainMethod;
|
||||
}
|
||||
|
||||
private boolean isSpringBootConfiguration(Class<?> candidate) {
|
||||
return MergedAnnotations.from(candidate, SearchStrategy.TYPE_HIERARCHY)
|
||||
.isPresent(SpringBootConfiguration.class);
|
||||
}
|
||||
|
||||
private void configure(MergedContextConfiguration mergedConfig, SpringApplication application) {
|
||||
application.setMainApplicationClass(mergedConfig.getTestClass());
|
||||
application.addPrimarySources(Arrays.asList(mergedConfig.getClasses()));
|
||||
application.getSources().addAll(Arrays.asList(mergedConfig.getLocations()));
|
||||
@@ -103,7 +152,8 @@ public class SpringBootContextLoader extends AbstractContextLoader {
|
||||
else {
|
||||
application.setWebApplicationType(WebApplicationType.NONE);
|
||||
}
|
||||
application.setApplicationContextFactory((type) -> getApplicationContextFactory(mergedConfig, type));
|
||||
application.setApplicationContextFactory(
|
||||
(webApplicationType) -> getApplicationContextFactory(mergedConfig, webApplicationType));
|
||||
application.setInitializers(initializers);
|
||||
ConfigurableEnvironment environment = getEnvironment();
|
||||
if (environment != null) {
|
||||
@@ -113,30 +163,19 @@ public class SpringBootContextLoader extends AbstractContextLoader {
|
||||
else {
|
||||
application.addListeners(new PrepareEnvironmentListener(mergedConfig));
|
||||
}
|
||||
String[] args = SpringBootTestArgs.get(mergedConfig.getContextCustomizers());
|
||||
return application.run(args);
|
||||
}
|
||||
|
||||
private void assertHasClassesOrLocations(MergedContextConfiguration mergedConfig) {
|
||||
boolean hasClasses = !ObjectUtils.isEmpty(mergedConfig.getClasses());
|
||||
boolean hasLocations = !ObjectUtils.isEmpty(mergedConfig.getLocations());
|
||||
Assert.state(hasClasses || hasLocations,
|
||||
() -> "No configuration classes or locations found in @SpringApplicationConfiguration. "
|
||||
+ "For default configuration detection to work you need Spring 4.0.3 or better (found "
|
||||
+ SpringVersion.getVersion() + ").");
|
||||
}
|
||||
|
||||
private ConfigurableApplicationContext getApplicationContextFactory(MergedContextConfiguration mergedConfig,
|
||||
WebApplicationType type) {
|
||||
if (type != WebApplicationType.NONE && !isEmbeddedWebEnvironment(mergedConfig)) {
|
||||
if (type == WebApplicationType.REACTIVE) {
|
||||
WebApplicationType webApplicationType) {
|
||||
if (webApplicationType != WebApplicationType.NONE && !isEmbeddedWebEnvironment(mergedConfig)) {
|
||||
if (webApplicationType == WebApplicationType.REACTIVE) {
|
||||
return new GenericReactiveWebApplicationContext();
|
||||
}
|
||||
if (type == WebApplicationType.SERVLET) {
|
||||
if (webApplicationType == WebApplicationType.SERVLET) {
|
||||
return new GenericWebApplicationContext();
|
||||
}
|
||||
}
|
||||
return ApplicationContextFactory.DEFAULT.create(type);
|
||||
return ApplicationContextFactory.DEFAULT.create(webApplicationType);
|
||||
}
|
||||
|
||||
private void prepareEnvironment(MergedContextConfiguration mergedConfig, SpringApplication application,
|
||||
@@ -165,9 +204,10 @@ public class SpringBootContextLoader extends AbstractContextLoader {
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds new {@link org.springframework.boot.SpringApplication} instance. You can
|
||||
* override this method to add custom behavior
|
||||
* @return {@link org.springframework.boot.SpringApplication} instance
|
||||
* Builds new {@link org.springframework.boot.SpringApplication} instance. This method
|
||||
* is only called when a {@code main} method isn't being used to create the
|
||||
* {@link SpringApplication}.
|
||||
* @return a {@link SpringApplication} instance
|
||||
*/
|
||||
protected SpringApplication getSpringApplication() {
|
||||
return new SpringApplication();
|
||||
@@ -215,16 +255,14 @@ public class SpringBootContextLoader extends AbstractContextLoader {
|
||||
initializers.add(BeanUtils.instantiateClass(initializerClass));
|
||||
}
|
||||
if (mergedConfig.getParent() != null) {
|
||||
initializers
|
||||
.add(new ParentContextApplicationContextInitializer(mergedConfig.getParentApplicationContext()));
|
||||
ApplicationContext parentApplicationContext = mergedConfig.getParentApplicationContext();
|
||||
initializers.add(new ParentContextApplicationContextInitializer(parentApplicationContext));
|
||||
}
|
||||
return initializers;
|
||||
}
|
||||
|
||||
private boolean isEmbeddedWebEnvironment(MergedContextConfiguration mergedConfig) {
|
||||
return MergedAnnotations.from(mergedConfig.getTestClass(), SearchStrategy.TYPE_HIERARCHY)
|
||||
.get(SpringBootTest.class).getValue("webEnvironment", WebEnvironment.class).orElse(WebEnvironment.NONE)
|
||||
.isEmbedded();
|
||||
return SpringBootTestAnnotation.get(mergedConfig).getWebEnvironment().isEmbedded();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -371,4 +409,45 @@ public class SpringBootContextLoader extends AbstractContextLoader {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link SpringApplicationHook} used to capture the {@link ApplicationContext} and to
|
||||
* trigger early exit for the {@link Mode#AOT_PROCESSING} mode.
|
||||
*/
|
||||
private class ContextLoaderHook implements SpringApplicationHook {
|
||||
|
||||
private final MergedContextConfiguration mergedConfig;
|
||||
|
||||
ContextLoaderHook(MergedContextConfiguration mergedConfig) {
|
||||
this.mergedConfig = mergedConfig;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpringApplicationRunListener getRunListener(SpringApplication application) {
|
||||
return new SpringApplicationRunListener() {
|
||||
|
||||
@Override
|
||||
public void starting(ConfigurableBootstrapContext bootstrapContext) {
|
||||
SpringBootContextLoader.this.configure(ContextLoaderHook.this.mergedConfig, application);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ready(ConfigurableApplicationContext context, Duration timeTaken) {
|
||||
throw new AbandonedRunException(context);
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
private <T> ApplicationContext run(ThrowingSupplier<T> action) {
|
||||
try {
|
||||
SpringApplication.withHook(this, action);
|
||||
throw new IllegalStateException("ApplicationContext not loaded");
|
||||
}
|
||||
catch (AbandonedRunException ex) {
|
||||
return ex.getApplicationContext();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -125,6 +125,14 @@ public @interface SpringBootTest {
|
||||
*/
|
||||
WebEnvironment webEnvironment() default WebEnvironment.MOCK;
|
||||
|
||||
/**
|
||||
* The type of main method usage to employ when creating the {@link SpringApplication}
|
||||
* under test.
|
||||
* @return the type of main method usage
|
||||
* @since 3.0.0
|
||||
*/
|
||||
UseMainMethod useMainMethod() default UseMainMethod.WHEN_AVAILABLE;
|
||||
|
||||
/**
|
||||
* An enumeration web environment modes.
|
||||
*/
|
||||
@@ -175,4 +183,34 @@ public @interface SpringBootTest {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Enumeration of how the main method of the
|
||||
* {@link SpringBootConfiguration @SpringBootConfiguration}-annotated class is used
|
||||
* when creating and running the {@link SpringApplication} under test.
|
||||
*/
|
||||
enum UseMainMethod {
|
||||
|
||||
/**
|
||||
* Always use the {@code main} method. A failure will occur if there is no
|
||||
* {@link SpringBootConfiguration @SpringBootConfiguration}-annotated class or
|
||||
* that class does not have a main method.
|
||||
*/
|
||||
ALWAYS,
|
||||
|
||||
/**
|
||||
* Never use the {@code main} method, creating a test-specific
|
||||
* {@link SpringApplication} instead.
|
||||
*/
|
||||
NEVER,
|
||||
|
||||
/**
|
||||
* Use the {@code main} method when it is available. If there is no
|
||||
* {@link SpringBootConfiguration @SpringBootConfiguration}-annotated class or
|
||||
* that class does not have a main method, a test-specific
|
||||
* {@link SpringApplication} will be used.
|
||||
*/
|
||||
WHEN_AVAILABLE;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright 2012-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.test.context;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.springframework.boot.test.context.SpringBootTest.UseMainMethod;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.test.context.ContextCustomizer;
|
||||
import org.springframework.test.context.MergedContextConfiguration;
|
||||
import org.springframework.test.context.TestContextAnnotationUtils;
|
||||
|
||||
/**
|
||||
* {@link ContextCustomizer} to track attributes of
|
||||
* {@link SpringBootTest @SptringBootTest} that are taken into account when evaluating a
|
||||
* {@link MergedContextConfiguration} to determine if a context can be shared between
|
||||
* tests.
|
||||
*
|
||||
* @author Phillip Webb
|
||||
* @author Madhura Bhave
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class SpringBootTestAnnotation implements ContextCustomizer {
|
||||
|
||||
private static final String[] NO_ARGS = new String[0];
|
||||
|
||||
private static final SpringBootTestAnnotation DEFAULT = new SpringBootTestAnnotation((SpringBootTest) null);
|
||||
|
||||
private final String[] args;
|
||||
|
||||
private final WebEnvironment webEnvironment;
|
||||
|
||||
private final UseMainMethod useMainMethod;
|
||||
|
||||
SpringBootTestAnnotation(Class<?> testClass) {
|
||||
this(TestContextAnnotationUtils.findMergedAnnotation(testClass, SpringBootTest.class));
|
||||
}
|
||||
|
||||
private SpringBootTestAnnotation(SpringBootTest annotation) {
|
||||
this.args = (annotation != null) ? annotation.args() : NO_ARGS;
|
||||
this.webEnvironment = (annotation != null) ? annotation.webEnvironment() : WebEnvironment.NONE;
|
||||
this.useMainMethod = (annotation != null) ? annotation.useMainMethod() : UseMainMethod.WHEN_AVAILABLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void customizeContext(ConfigurableApplicationContext context, MergedContextConfiguration mergedConfig) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (this == obj) {
|
||||
return true;
|
||||
}
|
||||
if (obj == null || getClass() != obj.getClass()) {
|
||||
return false;
|
||||
}
|
||||
SpringBootTestAnnotation other = (SpringBootTestAnnotation) obj;
|
||||
boolean result = Arrays.equals(this.args, other.args);
|
||||
result = result && this.useMainMethod == other.useMainMethod;
|
||||
result = result && this.webEnvironment == other.webEnvironment;
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
final int prime = 31;
|
||||
int result = 1;
|
||||
result = prime * result + Arrays.hashCode(this.args);
|
||||
result = prime * result + Objects.hash(this.useMainMethod, this.webEnvironment);
|
||||
return result;
|
||||
}
|
||||
|
||||
String[] getArgs() {
|
||||
return this.args;
|
||||
}
|
||||
|
||||
WebEnvironment getWebEnvironment() {
|
||||
return this.webEnvironment;
|
||||
}
|
||||
|
||||
UseMainMethod getUseMainMethod() {
|
||||
return this.useMainMethod;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the application arguments from the given {@link MergedContextConfiguration}.
|
||||
* @param mergedConfig the merged config to check
|
||||
* @return a {@link SpringBootTestAnnotation} instance
|
||||
*/
|
||||
static SpringBootTestAnnotation get(MergedContextConfiguration mergedConfig) {
|
||||
for (ContextCustomizer customizer : mergedConfig.getContextCustomizers()) {
|
||||
if (customizer instanceof SpringBootTestAnnotation annotation) {
|
||||
return annotation;
|
||||
}
|
||||
}
|
||||
return DEFAULT;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2022 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.test.context;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.core.annotation.MergedAnnotations;
|
||||
import org.springframework.test.context.ContextCustomizer;
|
||||
import org.springframework.test.context.MergedContextConfiguration;
|
||||
|
||||
/**
|
||||
* {@link ContextCustomizer} to track application arguments that are used in a
|
||||
* {@link SpringBootTest}. The application arguments are taken into account when
|
||||
* evaluating a {@link MergedContextConfiguration} to determine if a context can be shared
|
||||
* between tests.
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
class SpringBootTestArgs implements ContextCustomizer {
|
||||
|
||||
private static final String[] NO_ARGS = new String[0];
|
||||
|
||||
private final String[] args;
|
||||
|
||||
SpringBootTestArgs(Class<?> testClass) {
|
||||
this.args = MergedAnnotations.from(testClass, MergedAnnotations.SearchStrategy.TYPE_HIERARCHY)
|
||||
.get(SpringBootTest.class).getValue("args", String[].class).orElse(NO_ARGS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void customizeContext(ConfigurableApplicationContext context, MergedContextConfiguration mergedConfig) {
|
||||
}
|
||||
|
||||
String[] getArgs() {
|
||||
return this.args;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return (obj != null) && (getClass() == obj.getClass())
|
||||
&& Arrays.equals(this.args, ((SpringBootTestArgs) obj).args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return Arrays.hashCode(this.args);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the application arguments from the given customizers.
|
||||
* @param customizers the customizers to check
|
||||
* @return the application args or an empty array
|
||||
*/
|
||||
static String[] get(Set<ContextCustomizer> customizers) {
|
||||
for (ContextCustomizer customizer : customizers) {
|
||||
if (customizer instanceof SpringBootTestArgs testArgs) {
|
||||
return testArgs.args;
|
||||
}
|
||||
}
|
||||
return NO_ARGS;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -362,8 +362,7 @@ public class SpringBootTestContextBootstrapper extends DefaultTestContextBootstr
|
||||
protected final MergedContextConfiguration createModifiedConfig(MergedContextConfiguration mergedConfig,
|
||||
Class<?>[] classes, String[] propertySourceProperties) {
|
||||
Set<ContextCustomizer> contextCustomizers = new LinkedHashSet<>(mergedConfig.getContextCustomizers());
|
||||
contextCustomizers.add(new SpringBootTestArgs(mergedConfig.getTestClass()));
|
||||
contextCustomizers.add(new SpringBootTestWebEnvironment(mergedConfig.getTestClass()));
|
||||
contextCustomizers.add(new SpringBootTestAnnotation(mergedConfig.getTestClass()));
|
||||
return new MergedContextConfiguration(mergedConfig.getTestClass(), mergedConfig.getLocations(), classes,
|
||||
mergedConfig.getContextInitializerClasses(), mergedConfig.getActiveProfiles(),
|
||||
mergedConfig.getPropertySourceLocations(), propertySourceProperties, contextCustomizers,
|
||||
|
||||
@@ -1,58 +0,0 @@
|
||||
/*
|
||||
* Copyright 2012-2020 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.boot.test.context;
|
||||
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.test.context.ContextCustomizer;
|
||||
import org.springframework.test.context.MergedContextConfiguration;
|
||||
import org.springframework.test.context.TestContextAnnotationUtils;
|
||||
|
||||
/**
|
||||
* {@link ContextCustomizer} to track the web environment that is used in a
|
||||
* {@link SpringBootTest}. The web environment is taken into account when evaluating a
|
||||
* {@link MergedContextConfiguration} to determine if a context can be shared between
|
||||
* tests.
|
||||
*
|
||||
* @author Andy Wilkinson
|
||||
*/
|
||||
class SpringBootTestWebEnvironment implements ContextCustomizer {
|
||||
|
||||
private final WebEnvironment webEnvironment;
|
||||
|
||||
SpringBootTestWebEnvironment(Class<?> testClass) {
|
||||
SpringBootTest sprintBootTest = TestContextAnnotationUtils.findMergedAnnotation(testClass,
|
||||
SpringBootTest.class);
|
||||
this.webEnvironment = (sprintBootTest != null) ? sprintBootTest.webEnvironment() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void customizeContext(ConfigurableApplicationContext context, MergedContextConfiguration mergedConfig) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return (obj != null) && (getClass() == obj.getClass())
|
||||
&& this.webEnvironment == ((SpringBootTestWebEnvironment) obj).webEnvironment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return (this.webEnvironment != null) ? this.webEnvironment.hashCode() : 0;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -23,6 +23,9 @@ import java.util.stream.Collectors;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.SpringBootConfiguration;
|
||||
import org.springframework.boot.test.context.SpringBootTest.UseMainMethod;
|
||||
import org.springframework.boot.test.util.TestPropertyValues;
|
||||
import org.springframework.boot.web.reactive.context.GenericReactiveWebApplicationContext;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
@@ -40,6 +43,7 @@ import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
|
||||
|
||||
/**
|
||||
* Tests for {@link SpringBootContextLoader}
|
||||
@@ -114,8 +118,7 @@ class SpringBootContextLoaderTests {
|
||||
assertThat(getActiveProfiles(ActiveProfileWithComma.class)).containsExactly("profile1,2");
|
||||
}
|
||||
|
||||
@Test
|
||||
// gh-28776
|
||||
@Test // gh-28776
|
||||
void testPropertyValuesShouldTakePrecedenceWhenInlinedPropertiesPresent() {
|
||||
TestContext context = new ExposedTestContextManager(SimpleConfig.class).getExposedTestContext();
|
||||
StandardEnvironment environment = (StandardEnvironment) context.getApplicationContext().getEnvironment();
|
||||
@@ -162,6 +165,37 @@ class SpringBootContextLoaderTests {
|
||||
assertThat(context.getApplicationContext()).isInstanceOf(GenericReactiveWebApplicationContext.class);
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenUseMainMethodAlwaysAndMainMethodThrowsException() {
|
||||
TestContext testContext = new ExposedTestContextManager(UseMainMethodAlwaysAndMainMethodThrowsException.class)
|
||||
.getExposedTestContext();
|
||||
assertThatIllegalStateException().isThrownBy(testContext::getApplicationContext).havingCause()
|
||||
.withMessageContaining("ThrownFromMain");
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenUseMainMethodWhenAvailableAndNoMainMethod() {
|
||||
TestContext testContext = new ExposedTestContextManager(UseMainMethodWhenAvailableAndNoMainMethod.class)
|
||||
.getExposedTestContext();
|
||||
ApplicationContext applicationContext = testContext.getApplicationContext();
|
||||
assertThat(applicationContext.getEnvironment().getActiveProfiles()).isEmpty();
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenUseMainMethodWhenAvailableAndMainMethod() {
|
||||
TestContext testContext = new ExposedTestContextManager(UseMainMethodWhenAvailableAndMainMethod.class)
|
||||
.getExposedTestContext();
|
||||
ApplicationContext applicationContext = testContext.getApplicationContext();
|
||||
assertThat(applicationContext.getEnvironment().getActiveProfiles()).contains("frommain");
|
||||
}
|
||||
|
||||
@Test
|
||||
void whenUseMainMethodNever() {
|
||||
TestContext testContext = new ExposedTestContextManager(UseMainMethodNever.class).getExposedTestContext();
|
||||
ApplicationContext applicationContext = testContext.getApplicationContext();
|
||||
assertThat(applicationContext.getEnvironment().getActiveProfiles()).isEmpty();
|
||||
}
|
||||
|
||||
private String[] getActiveProfiles(Class<?> testClass) {
|
||||
TestContext testContext = new ExposedTestContextManager(testClass).getExposedTestContext();
|
||||
ApplicationContext applicationContext = testContext.getApplicationContext();
|
||||
@@ -239,11 +273,6 @@ class SpringBootContextLoaderTests {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class Config {
|
||||
|
||||
}
|
||||
|
||||
@SpringBootTest(classes = Config.class, args = "--spring.main.web-application-type=none")
|
||||
static class ChangingWebApplicationTypeToNone {
|
||||
|
||||
@@ -254,6 +283,57 @@ class SpringBootContextLoaderTests {
|
||||
|
||||
}
|
||||
|
||||
@SpringBootTest(classes = ConfigWithThrowingMain.class, useMainMethod = UseMainMethod.ALWAYS)
|
||||
static class UseMainMethodAlwaysAndMainMethodThrowsException {
|
||||
|
||||
}
|
||||
|
||||
@SpringBootTest(classes = ConfigWithNoMain.class, useMainMethod = UseMainMethod.WHEN_AVAILABLE)
|
||||
static class UseMainMethodWhenAvailableAndNoMainMethod {
|
||||
|
||||
}
|
||||
|
||||
@SpringBootTest(classes = ConfigWithMain.class, useMainMethod = UseMainMethod.WHEN_AVAILABLE)
|
||||
static class UseMainMethodWhenAvailableAndMainMethod {
|
||||
|
||||
}
|
||||
|
||||
@SpringBootTest(classes = ConfigWithMain.class, useMainMethod = UseMainMethod.NEVER)
|
||||
static class UseMainMethodNever {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
static class Config {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@SpringBootConfiguration
|
||||
public static class ConfigWithMain {
|
||||
|
||||
public static void main(String[] args) {
|
||||
new SpringApplication(ConfigWithMain.class).run("--spring.profiles.active=frommain");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@SpringBootConfiguration
|
||||
static class ConfigWithNoMain {
|
||||
|
||||
}
|
||||
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@SpringBootConfiguration
|
||||
public static class ConfigWithThrowingMain {
|
||||
|
||||
public static void main(String[] args) {
|
||||
throw new RuntimeException("ThrownFromMain");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* {@link TestContextManager} which exposes the {@link TestContext}.
|
||||
*/
|
||||
|
||||
@@ -21,6 +21,7 @@ import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.env.EnvironmentPostProcessor;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.UseMainMethod;
|
||||
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
@@ -33,7 +34,8 @@ import static org.assertj.core.api.Assertions.assertThat;
|
||||
*
|
||||
* @author Madhura Bhave
|
||||
*/
|
||||
@SpringBootTest(webEnvironment = WebEnvironment.NONE, properties = { "enableEnvironmentPostProcessor=true" }) // gh-28530
|
||||
@SpringBootTest(useMainMethod = UseMainMethod.NEVER, webEnvironment = WebEnvironment.NONE,
|
||||
properties = { "enableEnvironmentPostProcessor=true" }) // gh-28530
|
||||
@ActiveProfiles("hello")
|
||||
class ActiveProfilesTests {
|
||||
|
||||
|
||||
@@ -20,11 +20,12 @@ import org.junit.jupiter.api.Test;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.test.context.SpringBootTest.UseMainMethod;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
|
||||
// gh-29169
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||
@SpringBootTest(useMainMethod = UseMainMethod.NEVER, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
|
||||
class AttributeInjectionTests {
|
||||
|
||||
@Autowired(required = false)
|
||||
|
||||
Reference in New Issue
Block a user