Complete Spring Boot application context testing with automatic configuration detection, multiple web environment modes, and property/argument injection.
org.springframework.boot.test.context
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.server.LocalServerPort;
import org.springframework.boot.test.web.server.LocalManagementPort;
import org.springframework.beans.factory.annotation.Autowired;
import org.junit.jupiter.api.Test;Full Package: org.springframework.boot.test.context.SpringBootTest
Since: 1.4.0
Main annotation for Spring Boot integration tests that loads full application context with Spring Boot features including auto-configuration, custom Environment properties, application arguments, and multiple web environment modes.
/**
* Annotation for Spring Boot integration tests
* Triggers SpringBootTestContextBootstrapper for custom test context setup
* Automatically searches for @SpringBootConfiguration if classes not specified
* @since 1.4.0
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@BootstrapWith(SpringBootTestContextBootstrapper.class)
@ExtendWith(SpringExtension.class)
public @interface SpringBootTest {
/**
* Alias for properties() - use for simple property definitions
* Convenient shorthand when only defining properties
* @return properties in key=value format
*/
String[] value() default {};
/**
* Properties in key=value format added to Environment before test runs
* Properties have higher precedence than application.properties
* Format: "key=value" or "key:value"
* Example: {"server.port=0", "spring.datasource.url=jdbc:h2:mem:testdb"}
* @return property definitions
*/
String[] properties() default {};
/**
* Application arguments passed to main method
* Only used when useMainMethod != NEVER
* Format: standard command-line args like "--debug" or "--spring.profiles.active=test"
* @return application arguments
* @since 2.2.0
*/
String[] args() default {};
/**
* Configuration classes for the application context
* If empty, searches for @SpringBootConfiguration in package hierarchy
* Useful for limiting context to specific configurations
* @return configuration classes
*/
Class<?>[] classes() default {};
/**
* Web environment mode for the test
* Determines if/how an embedded web server is started
* @return the web environment mode (defaults to MOCK)
*/
WebEnvironment webEnvironment() default WebEnvironment.MOCK;
/**
* Whether to use the application main method for context initialization
* ALWAYS: Always invoke main method
* NEVER: Never invoke main method (standard Spring Boot test behavior)
* WHEN_AVAILABLE: Invoke if main method exists
* @return main method usage mode (defaults to NEVER)
* @since 3.0.0
*/
UseMainMethod useMainMethod() default UseMainMethod.NEVER;
/**
* Web environment modes for integration tests
* Determines how the application context is configured for web testing
*/
enum WebEnvironment {
/**
* Mock web environment - loads WebApplicationContext with MockMvc support
* No embedded server is started
* Use with @AutoConfigureMockMvc for MockMvc testing
* Suitable for controller layer testing without network stack
*/
MOCK,
/**
* Start embedded web server on a random available port
* Ideal for integration tests to avoid port conflicts
* Port can be injected with @LocalServerPort
* Creates full network stack for realistic testing
*/
RANDOM_PORT,
/**
* Start embedded server on the port defined in properties
* Uses server.port from configuration (default 8080)
* Can cause port conflicts if not managed carefully
* Useful when tests need predictable port numbers
*/
DEFINED_PORT,
/**
* No web environment - loads standard ApplicationContext
* Use for testing non-web components or services
* Lighter weight than MOCK as no web infrastructure is loaded
* Best for business logic and data layer testing
*/
NONE;
/**
* Check if this environment uses an embedded web server
* @return true for RANDOM_PORT and DEFINED_PORT, false for MOCK and NONE
*/
public boolean isEmbedded();
}
/**
* Main method usage modes
* Controls whether the application main method is invoked during test setup
*/
enum UseMainMethod {
/**
* Always use the main method for context initialization
* Test fails if main method not found
* Ensures test environment matches production startup
*/
ALWAYS,
/**
* Never use the main method (default behavior)
* Standard Spring Boot test context initialization
* Faster and more predictable for most tests
*/
NEVER,
/**
* Use main method when available, fall back to standard if not
* Flexible option for shared test infrastructure
* Useful in multi-module projects with varying main method presence
*/
WHEN_AVAILABLE
}
}import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.beans.factory.annotation.Autowired;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest
class BasicIntegrationTest {
@Autowired
private MyService service;
@Test
void testServiceMethod() {
assertThat(service.process("input")).isNotNull();
}
}import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.test.web.server.LocalServerPort;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.http.HttpStatus;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class RandomPortTest {
@LocalServerPort
private int port; // Injected after server starts
@Autowired
private TestRestTemplate restTemplate; // Auto-configured
@Test
void testEndpoint() {
ResponseEntity<String> response = restTemplate.getForEntity(
"/api/test", String.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
}
}@SpringBootTest(properties = {
"spring.datasource.url=jdbc:h2:mem:testdb",
"custom.feature.enabled=true",
"server.port=0" // 0 for random port
})
class PropertiesTest {
// Properties are added to Environment before context starts
}@SpringBootTest(classes = {TestConfig.class, ServiceConfig.class})
class CustomConfigTest {
// Only specified configurations are loaded
// Auto-configuration still applies unless excluded
}Full Package: org.springframework.boot.test.web.server.LocalServerPort
Since: 2.7.0
Injects the HTTP server port that was allocated at runtime. Provides a convenient alternative for @Value("${local.server.port}").
/**
* Annotation at the field or method/constructor parameter level that injects the HTTP
* server port that was allocated at runtime. Provides a convenient alternative for
* @Value("${local.server.port}") with the assumption that the
* web server implementation has configured such a property.
* @since 2.7.0
*/
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Value("${local.server.port}")
public @interface LocalServerPort {
}Usage:
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class PortInjectionTest {
@LocalServerPort
private int port; // Injects actual server port
}Constraints:
Full Package: org.springframework.boot.test.web.server.LocalManagementPort
Since: 2.7.0
Injects the HTTP management port that was allocated at runtime when management server is configured separately. Provides a convenient alternative for @Value("${local.management.port}").
/**
* Annotation at the field or method/constructor parameter level that injects the HTTP
* management port that was allocated at runtime. Provides a convenient alternative for
* @Value("${local.management.port}") with the assumption that the management web
* server implementation has configured such a property.
* @since 2.7.0
*/
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Value("${local.management.port}")
public @interface LocalManagementPort {
}Usage:
@SpringBootTest(
webEnvironment = WebEnvironment.RANDOM_PORT,
properties = "management.server.port=0"
)
class ManagementPortTest {
@LocalManagementPort
private int managementPort;
}Full Package: org.springframework.boot.test.context.PropertyMapping
Since: 4.0.0
Maps test annotation attributes to environment properties for declarative configuration.
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface PropertyMapping {
String value() default ""; // Property name or prefix
Skip skip() default Skip.NO;
enum Skip {
YES, // Skip mapping this property
ON_DEFAULT_VALUE, // Skip if default value
NO // Always map (default)
}
}Usage Pattern:
// Define custom test annotation with property mapping
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@PropertyMapping("app.test")
public @interface TestWithConfig {
String environment() default "test";
@PropertyMapping(skip = PropertyMapping.Skip.ON_DEFAULT_VALUE)
String optionalValue() default "";
}
// Use annotation - maps to app.test.environment and app.test.optional-value
@SpringBootTest
@TestWithConfig(environment = "integration")
class MyTest {
@Value("${app.test.environment}")
private String env; // injected as "integration"
}Full Package: org.springframework.boot.test.context.filter.annotation.TypeExcludeFilters
Since: 4.0.0
Registers TypeExcludeFilter classes for component scanning control. Filters can be used to exclude specific types from being registered with the ApplicationContext during tests.
/**
* Annotation that can be on tests to define a set of TypeExcludeFilter classes
* that should be registered with the ApplicationContext.
* Filter classes can either have a no-arg constructor or accept a single
* Class<?> argument if they need access to the testClass.
* @since 4.0.0
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface TypeExcludeFilters {
/**
* Specifies TypeExcludeFilter classes that should be registered
* @return the type exclude filters to apply
*/
Class<? extends TypeExcludeFilter>[] value();
}Usage Pattern:
// Custom filter implementation
public class TestComponentFilter extends TypeExcludeFilter {
@Override
public boolean match(MetadataReader reader, MetadataReaderFactory factory) {
return reader.getClassMetadata().getClassName().contains("Mock");
}
}
// Apply filter to test
@SpringBootTest
@TypeExcludeFilters(TestComponentFilter.class)
class FilteredTest {
// Mock components excluded from context
}Full Package: org.springframework.boot.test.context.SpringBootContextLoader
Since: 1.4.0
Context loader for @SpringBootTest. Uses SpringApplication for proper initialization.
public class SpringBootContextLoader extends AbstractContextLoader implements AotContextLoader {
// Load context for test execution
public ApplicationContext loadContext(MergedContextConfiguration config) throws Exception;
// AOT processing support (since 3.0.0)
public ApplicationContext loadContextForAotProcessing(
MergedContextConfiguration config, RuntimeHints hints) throws Exception;
public ApplicationContext loadContextForAotRuntime(
MergedContextConfiguration config,
ApplicationContextInitializer<ConfigurableApplicationContext> initializer) throws Exception;
@Override
public void processContextConfiguration(ContextConfigurationAttributes attrs);
}Full Package: org.springframework.boot.test.context.SpringBootTestContextBootstrapper
Since: 1.4.0
public class SpringBootTestContextBootstrapper extends DefaultTestContextBootstrapper {
public SpringBootTestContextBootstrapper();
@Override
public TestContext buildTestContext();
}Full Package: org.springframework.boot.test.context.ReactiveWebMergedContextConfiguration
Since: 2.0.0
public class ReactiveWebMergedContextConfiguration extends MergedContextConfiguration {
public ReactiveWebMergedContextConfiguration(MergedContextConfiguration mergedConfig);
}Full Package: org.springframework.boot.test.context.SpringBootTestAotProcessor
Since: 3.0.0
AOT processor for Spring Boot test classes. For framework use only.
public class SpringBootTestAotProcessor extends TestAotProcessor {
public SpringBootTestAotProcessor(Set<Path> classpathRoots, Settings settings);
// Entry point for command-line AOT processing
public static void main(String[] args);
}Full Package: org.springframework.boot.test.context.ConfigDataApplicationContextInitializer
Since: 2.4.0
Loads application.properties/yaml for tests. Can be used with @ContextConfiguration.
public class ConfigDataApplicationContextInitializer
implements ApplicationContextInitializer<ConfigurableApplicationContext> {
public ConfigDataApplicationContextInitializer();
@Override
public void initialize(ConfigurableApplicationContext context);
}Usage:
@ContextConfiguration(
classes = MyConfig.class,
initializers = ConfigDataApplicationContextInitializer.class
)
class ConfigDataTest {
// application.properties loaded automatically
}Full Package: org.springframework.boot.test.context.AnnotatedClassFinder
Since: 2.1.0
Finds classes annotated with specific annotations in package hierarchy.
public final class AnnotatedClassFinder {
public AnnotatedClassFinder(Class<? extends Annotation> annotationType);
@Nullable
public Class<?> findFromClass(Class<?> source);
@Nullable
public Class<?> findFromPackage(String source);
}Usage:
// Find @SpringBootConfiguration from test class
AnnotatedClassFinder finder =
new AnnotatedClassFinder(SpringBootConfiguration.class);
Class<?> config = finder.findFromClass(MyTest.class);Full Package: org.springframework.boot.test.context.FilteredClassLoader
Since: 2.0.0
Test ClassLoader that filters classes and resources to simulate classpath scenarios.
/**
* Test URLClassLoader that can filter the classes and resources it can load
* Used to test auto-configuration behavior when specific classes are absent
* @since 2.0.0
*/
public class FilteredClassLoader extends URLClassLoader implements SmartClassLoader {
/**
* Create a FilteredClassLoader that hides the given classes
* @param hiddenClasses the classes to hide
*/
public FilteredClassLoader(Class<?>... hiddenClasses);
/**
* Create a FilteredClassLoader with the given parent that hides the given classes
* @param parent the parent class loader
* @param hiddenClasses the classes to hide
*/
public FilteredClassLoader(ClassLoader parent, Class<?>... hiddenClasses);
/**
* Create a FilteredClassLoader that hides classes from the given packages
* @param hiddenPackages the packages to hide
*/
public FilteredClassLoader(String... hiddenPackages);
/**
* Create a FilteredClassLoader that hides resources from the given ClassPathResources
* @param hiddenResources the resources to hide
* @since 2.1.0
*/
public FilteredClassLoader(ClassPathResource... hiddenResources);
/**
* Create a FilteredClassLoader that filters based on the given predicate
* @param filters a set of filters to determine when a class name or resource should be hidden
*/
public FilteredClassLoader(Predicate<String>... filters);
/**
* Filter to restrict the classes that can be loaded
*/
public static final class ClassFilter implements Predicate<String> {
public static ClassFilter of(Class<?>... hiddenClasses);
public boolean test(String className);
}
/**
* Filter to restrict the packages that can be loaded
*/
public static final class PackageFilter implements Predicate<String> {
public static PackageFilter of(String... hiddenPackages);
public boolean test(String className);
}
/**
* Filter to restrict the resources that can be loaded
* @since 2.1.0
*/
public static final class ClassPathResourceFilter implements Predicate<String> {
public static ClassPathResourceFilter of(ClassPathResource... hiddenResources);
public boolean test(String resourceName);
}
}Usage Examples:
import org.springframework.boot.test.context.FilteredClassLoader;
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
// Test auto-configuration when Jackson is not available
new ApplicationContextRunner()
.withClassLoader(new FilteredClassLoader(
com.fasterxml.jackson.databind.ObjectMapper.class))
.withUserConfiguration(JacksonAutoConfiguration.class)
.run(context ->
assertThat(context).doesNotHaveBean(ObjectMapper.class));
// Hide entire package
new ApplicationContextRunner()
.withClassLoader(new FilteredClassLoader("com.example.optional"))
.run(context -> {
// Test behavior when optional package not present
});
// Hide specific classpath resources
ClassPathResource resource = new ClassPathResource("META-INF/spring.factories");
new ApplicationContextRunner()
.withClassLoader(new FilteredClassLoader(resource))
.run(context -> {
// Test behavior when resource is missing
});Full Package: org.springframework.boot.test.context.filter.annotation.AnnotationCustomizableTypeExcludeFilter
Since: 4.0.0
Abstract base for annotation-based type filters. For custom test slice creation.
import org.springframework.context.annotation.ComponentScan.Filter;
public abstract class AnnotationCustomizableTypeExcludeFilter
extends TypeExcludeFilter implements BeanClassLoaderAware {
@Override
public void setBeanClassLoader(ClassLoader classLoader);
@Override
public boolean match(MetadataReader reader, MetadataReaderFactory factory)
throws IOException;
protected abstract boolean hasAnnotation();
protected abstract Filter[] getFilters(FilterType type);
protected abstract boolean isUseDefaultFilters();
protected abstract Set<Class<?>> getDefaultIncludes();
protected abstract Set<Class<?>> getComponentIncludes();
protected enum FilterType { INCLUDE, EXCLUDE }
}Full Package: org.springframework.boot.test.context.filter.annotation.StandardAnnotationCustomizableTypeExcludeFilter<A>
Since: 4.0.0
Generic implementation for standard filter annotations. Simplifies custom slice creation.
public abstract class StandardAnnotationCustomizableTypeExcludeFilter<A extends Annotation>
extends AnnotationCustomizableTypeExcludeFilter {
protected StandardAnnotationCustomizableTypeExcludeFilter(Class<?> testClass);
protected final MergedAnnotation<A> getAnnotation();
protected Class<A> getAnnotationType();
protected Set<Class<?>> getKnownIncludes();
}Usage Pattern:
import org.springframework.context.annotation.ComponentScan.Filter;
// Define custom slice annotation
@Retention(RetentionPolicy.RUNTIME)
@TypeExcludeFilters(MySliceFilter.class)
public @interface MySlice {
Filter[] includeFilters() default {};
Filter[] excludeFilters() default {};
boolean useDefaultFilters() default true;
}
// Implement filter
public class MySliceFilter extends StandardAnnotationCustomizableTypeExcludeFilter<MySlice> {
public MySliceFilter(Class<?> testClass) {
super(testClass);
}
@Override
protected Set<Class<?>> getKnownIncludes() {
return Set.of(MyComponent.class, MyService.class);
}
@Override
protected Set<Class<?>> getComponentIncludes() {
return Set.of(org.springframework.stereotype.Component.class);
}
}
// Use custom slice
@MySlice
class CustomSliceTest {
// Only MyComponent and MyService types loaded
}import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.reactive.server.WebTestClient;
import org.springframework.beans.factory.annotation.Autowired;
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class WebTestClientTest {
@Autowired
private WebTestClient webTestClient;
@Test
void testReactiveEndpoint() {
webTestClient.get()
.uri("/api/reactive")
.exchange()
.expectStatus().isOk()
.expectBody(String.class)
.value(body -> assertThat(body).isNotEmpty());
}
}import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Bean;
@SpringBootTest
class TestWithCustomConfig {
@TestConfiguration
static class Config {
@Bean
public MyService testService() {
return new MyTestService();
}
}
@Autowired
private MyService myService;
@Test
void testWithTestConfig() {
assertThat(myService).isInstanceOf(MyTestService.class);
}
}import org.springframework.boot.ApplicationArguments;
@SpringBootTest(args = {"--debug", "--custom.arg=value"})
class ApplicationArgumentsTest {
@Autowired
private ApplicationArguments args;
@Test
void testArguments() {
assertThat(args.containsOption("debug")).isTrue();
assertThat(args.getOptionValues("custom.arg")).contains("value");
}
}@SpringBootTest(webEnvironment = WebEnvironment.NONE)
class NonWebIntegrationTest {
@Autowired
private DataService dataService;
@Test
void testDataService() {
assertThat(dataService.getData()).isNotEmpty();
}
}@SpringBootTest(classes = {
TestConfig.class,
ServiceConfig.class,
DataSourceConfig.class
})
class MultiConfigTest {
@Autowired
private ApplicationContext context;
@Test
void verifyAllConfigsLoaded() {
assertThat(context).hasBean("testBean");
assertThat(context).hasBean("serviceBean");
assertThat(context).hasBean("dataSourceBean");
}
}import org.springframework.test.context.ActiveProfiles;
@SpringBootTest(properties = {
"spring.profiles.active=test",
"spring.datasource.url=jdbc:h2:mem:testdb"
})
@ActiveProfiles("test")
class ProfileTest {
@Value("${spring.datasource.url}")
private String datasourceUrl;
@Test
void testProfileProperties() {
assertThat(datasourceUrl).contains("h2:mem");
}
}import org.springframework.scheduling.annotation.EnableAsync;
import java.util.concurrent.CompletableFuture;
@SpringBootTest
@EnableAsync
class AsyncTest {
@Autowired
private AsyncService asyncService;
@Test
void testAsyncMethod() throws Exception {
CompletableFuture<String> result = asyncService.performAsync();
assertThat(result.get()).isEqualTo("async result");
}
}import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
class ParentContextTest {
@Test
void testWithParentContext() {
ApplicationContext parent = new AnnotationConfigApplicationContext(ParentConfig.class);
// Child context can access parent beans
// Note: Requires custom setup, not directly supported by @SpringBootTest
}
}Issue: NoSuchBeanDefinitionException in @SpringBootTest
@SpringBootTest(classes = {MyApplication.class, TestConfig.class})
class MyTest { }Issue: Port not injected (value is 0)
Issue: Properties not applied
properties = {"server.port=8080"} not "server.port: 8080"Issue: Context loads too slowly
Issue: TestRestTemplate returns null
Issue: Beans from @TestConfiguration not found
Issue: Context fails to start with circular dependency
Issue: Wrong database being used in tests
Issue: Main method arguments not passed
Issue: Management port injection fails
Error: "Unable to find @SpringBootConfiguration"
Error: "Failed to load ApplicationContext"
Error: "Port already in use"
Error: "Bean definition names clash"
spring.main.lazy-initialization=true in tests@SpringBootTest(exclude = {...}) for unused features