Spring Boot Test provides comprehensive testing support and utilities for Spring Boot applications
npx @tessl/cli install tessl/maven-org-springframework-boot--spring-boot-test@4.0.0Spring Boot Test is a comprehensive testing library that provides specialized annotations, utilities, and auto-configuration capabilities for testing Spring Boot applications. It offers full integration testing with @SpringBootTest, isolated slice testing with context runners, extensive JSON testing support, output capture utilities, and rich AssertJ-based assertions for validating application contexts and beans.
org.springframework.boot.testMaven:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-test</artifactId>
<version>4.0.0</version>
<scope>test</scope>
</dependency>Gradle:
testImplementation 'org.springframework.boot:spring-boot-test:4.0.0'org.springframework.boot.test
├── context # Integration testing (@SpringBootTest, context runners)
├── json # JSON testing (JacksonTester, GsonTester, JsonbTester)
├── system # Output capture utilities
├── web # Web testing utilities (HtmlUnit integration)
├── mock.web # Mock servlet context
└── http.server # Local test server utilities// Integration Testing
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
// Context Runners
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.springframework.boot.test.context.runner.WebApplicationContextRunner;
import org.springframework.boot.test.context.runner.ReactiveWebApplicationContextRunner;
// JSON Testing
import org.springframework.boot.test.json.JacksonTester;
import org.springframework.boot.test.json.GsonTester;
import org.springframework.boot.test.json.JsonbTester;
import org.springframework.boot.test.json.BasicJsonTester;
import org.springframework.boot.test.json.JsonContent;
// Output Capture
import org.springframework.boot.test.system.OutputCaptureExtension;
import org.springframework.boot.test.system.CapturedOutput;
// AssertJ Integration
import org.springframework.boot.test.context.assertj.AssertableApplicationContext;
import static org.assertj.core.api.Assertions.assertThat;
// Test Properties
import org.springframework.boot.test.util.TestPropertyValues;
import org.springframework.boot.test.util.ApplicationContextTestUtils;
// Test Configuration
import org.springframework.boot.test.context.FilteredClassLoader;
// Web Testing
import org.springframework.boot.test.http.server.LocalTestWebServer;
import org.springframework.boot.test.web.htmlunit.UriBuilderFactoryWebClient;
import org.springframework.boot.test.mock.web.SpringBootMockServletContext;Complete working example with all necessary imports and annotations:
package com.example.demo;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.beans.factory.annotation.Autowired;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class MyApplicationTests {
@Autowired
private MyService myService;
@Test
void testServiceMethod() {
String result = myService.process("test");
assertThat(result).isEqualTo("processed: test");
}
}Full integration testing with complete Spring Boot application context, supporting multiple web environment modes and automatic configuration detection.
Key Classes:
@SpringBootTest - Main annotation for integration tests (since 1.4.0)@LocalServerPort - Inject random server port (since 2.7.0)@LocalManagementPort - Inject management server port (since 2.7.0)@PropertyMapping - Map test annotation attributes to properties (since 4.0.0)@TypeExcludeFilters - Register type exclude filters (since 4.0.0)When to Use: Full application context testing with all auto-configurations
Package: org.springframework.boot.test.context
// Example usage:
@SpringBootTest(
properties = {"spring.datasource.url=jdbc:h2:mem:testdb", "server.port=0"},
args = {"--debug", "--spring.profiles.active=test"},
classes = {MyTestConfiguration.class},
webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
useMainMethod = SpringBootTest.UseMainMethod.NEVER
)
class MyIntegrationTest { }
/**
* Annotation for Spring Boot integration tests
* Provides automatic SpringBootConfiguration detection, custom Environment properties,
* application arguments, multiple web environment modes, and test context caching
* @since 1.4.0
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@BootstrapWith(SpringBootTestContextBootstrapper.class)
@ExtendWith(SpringExtension.class)
public @interface SpringBootTest {
/**
* Alias for properties()
* @return properties in key=value format
*/
String[] value() default {};
/**
* Properties in key=value format to add to Environment
* @return property definitions
*/
String[] properties() default {};
/**
* Application arguments passed to the application
* @return application arguments
* @since 2.2.0
*/
String[] args() default {};
/**
* Configuration classes for the application context.
* If not specified, searches for @SpringBootConfiguration
* @return configuration classes
*/
Class<?>[] classes() default {};
/**
* Web environment mode for the test
* @return the web environment mode
*/
WebEnvironment webEnvironment() default WebEnvironment.MOCK;
/**
* Whether to use the application main method
* @return main method usage mode
* @since 3.0.0
*/
UseMainMethod useMainMethod() default UseMainMethod.NEVER;
/**
* Web environment modes for integration tests
*/
enum WebEnvironment {
/** Mock web environment with MockMvc, no server started */
MOCK,
/** Start embedded server on random available port */
RANDOM_PORT,
/** Start embedded server on defined port from properties */
DEFINED_PORT,
/** No web environment, standard ApplicationContext */
NONE;
/**
* Return if the environment uses an embedded web server
* @return true for RANDOM_PORT and DEFINED_PORT
*/
public boolean isEmbedded();
}
/**
* Main method usage modes
*/
enum UseMainMethod {
/** Always use the main method */
ALWAYS,
/** Never use the main method */
NEVER,
/** Use main method when available */
WHEN_AVAILABLE
}
}
/**
* Map test annotation attributes to properties
* Indicates that attributes from a test annotation should be mapped into properties
* Can be used at type level to define prefix, or on individual attributes to customize mapping
* @since 4.0.0
*/
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface PropertyMapping {
/**
* Property mapping prefix (type-level) or property name override (attribute-level)
* @return the property mapping
*/
String value() default "";
/**
* Controls when mapping should be skipped
* @return skip mode
*/
Skip skip() default Skip.NO;
/**
* Skip modes for property mapping
*/
enum Skip {
/** Skip mapping the property */
YES,
/** Skip mapping when default attribute value is specified */
ON_DEFAULT_VALUE,
/** Don't skip mapping */
NO
}
}Lightweight application context testing without full application startup, ideal for testing auto-configurations and specific components in isolation.
Key Classes:
ApplicationContextRunner - Standard context testing (since 2.0.0)WebApplicationContextRunner - Servlet web context testing (since 2.0.0)ReactiveWebApplicationContextRunner - Reactive web context testing (since 2.0.0)When to Use: Isolated component testing, auto-configuration testing, unit-style tests with minimal context
Package: org.springframework.boot.test.context.runner
// Example usage:
new ApplicationContextRunner()
.withUserConfiguration(MyAutoConfiguration.class)
.withPropertyValues("feature.enabled=true", "feature.timeout=5000")
.withBean("myBean", MyService.class, () -> new MyServiceImpl())
.run(context -> {
assertThat(context).hasSingleBean(MyService.class);
assertThat(context).hasBean("myBean");
});
/**
* Context runner for ApplicationContext
* Provides fluent API for configuring and running an application context for tests
* @since 2.0.0
*/
public final class ApplicationContextRunner
extends AbstractApplicationContextRunner<ApplicationContextRunner, ConfigurableApplicationContext, AssertableApplicationContext> {
/**
* Create a new ApplicationContextRunner with default configuration
*/
public ApplicationContextRunner();
/**
* Create with a custom supplier for the application context
* @param contextFactory factory to create the application context
*/
public ApplicationContextRunner(Supplier<ConfigurableApplicationContext> contextFactory);
// Inherited from AbstractApplicationContextRunner:
// - withUserConfiguration(Class<?>... classes)
// - withConfiguration(Configurations configurations)
// - withPropertyValues(String... pairs)
// - withSystemProperties(String... pairs)
// - withBean(String name, Class<T> type, Supplier<T> supplier, BeanDefinitionCustomizer... customizers)
// - withInitializer(ApplicationContextInitializer<? super C> initializer)
// - withClassLoader(ClassLoader classLoader)
// - withParent(ApplicationContext parent)
// - run(ContextConsumer<? super A> consumer)
// - prepare(ContextConsumer<? super A> consumer)
}
// Example usage for web contexts:
new WebApplicationContextRunner()
.withUserConfiguration(WebMvcConfig.class)
.run(context -> assertThat(context).hasSingleBean(DispatcherServlet.class));
/**
* Context runner for WebApplicationContext
* @since 2.0.0
*/
public final class WebApplicationContextRunner
extends AbstractApplicationContextRunner<WebApplicationContextRunner, ConfigurableWebApplicationContext, AssertableWebApplicationContext> {
public WebApplicationContextRunner();
public WebApplicationContextRunner(Supplier<ConfigurableWebApplicationContext> contextFactory);
}
// Example usage for reactive contexts:
new ReactiveWebApplicationContextRunner()
.withUserConfiguration(WebFluxConfig.class)
.run(context -> assertThat(context).hasSingleBean(DispatcherHandler.class));
/**
* Context runner for ReactiveWebApplicationContext
* @since 2.0.0
*/
public final class ReactiveWebApplicationContextRunner
extends AbstractApplicationContextRunner<ReactiveWebApplicationContextRunner, ConfigurableReactiveWebApplicationContext, AssertableReactiveWebApplicationContext> {
public ReactiveWebApplicationContextRunner();
public ReactiveWebApplicationContextRunner(Supplier<ConfigurableReactiveWebApplicationContext> contextFactory);
}Comprehensive JSON serialization and deserialization testing with multiple library support (Jackson 3, Jackson 2, Gson, JSON-B) and extensive JSON path assertions.
Key Classes:
JacksonTester<T> - Jackson 3 testing (recommended, since 1.4.0, updated 4.0.0)Jackson2Tester<T> - Jackson 2 testing (deprecated since 4.0.0, removed in 4.2.0)GsonTester<T> - Gson testing (since 1.4.0)JsonbTester<T> - JSON-B testing (since 2.0.0)BasicJsonTester - Raw JSON string testing (since 1.4.0)JsonContent<T> - JSON content wrapper with assertions (since 1.4.0)ObjectContent<T> - Deserialized object wrapper (since 1.4.0)JsonContentAssert - AssertJ assertions for JSON (since 1.4.0)When to Use: Testing REST API JSON responses, verifying serialization/deserialization
Package: org.springframework.boot.test.json
// Example usage:
private JacksonTester<User> json;
@BeforeEach
void setup() {
JacksonTester.initFields(this, JsonMapper.builder().build());
}
@Test
void testSerialization() throws Exception {
User user = new User("alice", "alice@example.com");
assertThat(json.write(user))
.hasJsonPathStringValue("$.name", "alice")
.extractingJsonPathStringValue("$.email")
.isEqualTo("alice@example.com");
}
/**
* AssertJ-based JSON tester backed by Jackson 3 (tools.jackson)
* @param <T> the type under test
* @since 1.4.0 (updated for Jackson 3 in 4.0.0)
*/
public class JacksonTester<T> extends AbstractJsonMarshalTester<T> {
/**
* Create a new uninitialized JacksonTester instance
* @param jsonMapper the Jackson JSON mapper
* @since 4.0.0
*/
protected JacksonTester(JsonMapper jsonMapper);
/**
* Create a new JacksonTester instance
* @param resourceLoadClass the source class used to load resources
* @param type the type under test
* @param jsonMapper the Jackson JSON mapper
* @since 4.0.0
*/
public JacksonTester(Class<?> resourceLoadClass, ResolvableType type, JsonMapper jsonMapper);
/**
* Create a new JacksonTester instance with JSON view support
* @param resourceLoadClass the source class used to load resources
* @param type the type under test
* @param jsonMapper the Jackson JSON mapper
* @param view the JSON view class
*/
public JacksonTester(Class<?> resourceLoadClass, ResolvableType type, JsonMapper jsonMapper, Class<?> view);
/**
* Initialize all JacksonTester fields in a test instance
* Uses reflection to find and initialize all JacksonTester fields
* @param testInstance the test instance
* @param jsonMapper the Jackson JSON mapper
*/
public static void initFields(Object testInstance, JsonMapper jsonMapper);
/**
* Initialize all JacksonTester fields using a mapper factory
* @param testInstance the test instance
* @param jsonMapperFactory factory to create the JSON mapper
*/
public static void initFields(Object testInstance, ObjectFactory<JsonMapper> jsonMapperFactory);
/**
* Create a new tester instance with a specific JSON view
* @param view the JSON view class
* @return new JacksonTester instance configured with the view
*/
public JacksonTester<T> forView(Class<?> view);
// Inherits from AbstractJsonMarshalTester:
// - JsonContent<T> write(T value) throws IOException
// - T parseObject(String jsonString) throws IOException
// - T parseObject(byte[] jsonBytes) throws IOException
// - ObjectContent<T> parse(String jsonString) throws IOException
// - ObjectContent<T> parse(byte[] jsonBytes) throws IOException
// - T readObject(String resourcePath) throws IOException
// - T readObject(File file) throws IOException
// - T readObject(InputStream inputStream) throws IOException
// - ObjectContent<T> read(String resourcePath) throws IOException
// - ObjectContent<T> read(File file) throws IOException
// - ObjectContent<T> read(InputStream inputStream) throws IOException
}
/**
* JSON content wrapper with AssertJ assertion support
* @param <T> the source type that created the content
* @since 1.4.0
*/
public final class JsonContent<T> implements AssertProvider<JsonContentAssert> {
/**
* Create a new JsonContent instance
* @param resourceLoadClass the source class used to load resources
* @param type the type under test (or null if not known)
* @param json the actual JSON content
*/
public JsonContent(Class<?> resourceLoadClass, ResolvableType type, String json);
/**
* Get the actual JSON content string
* @return the JSON content
*/
public String getJson();
/**
* Get AssertJ assertions for this content
* @return JsonContentAssert instance
* @deprecated since 1.5.7, use AssertJ's assertThat(jsonContent) instead
*/
@Deprecated(since = "1.5.7", forRemoval = false)
public JsonContentAssert assertThat();
}
/**
* AssertJ assertions for JSON content validation
* @since 1.4.0
*/
public class JsonContentAssert extends AbstractAssert<JsonContentAssert, CharSequence> {
// Lenient equality assertions (ignores array order, extensible objects)
public JsonContentAssert isEqualToJson(CharSequence expected);
public JsonContentAssert isEqualToJson(String path, Class<?> resourceLoadClass);
public JsonContentAssert isEqualToJson(byte[] expected);
public JsonContentAssert isEqualToJson(File expected);
public JsonContentAssert isEqualToJson(InputStream expected);
public JsonContentAssert isEqualToJson(Resource expected);
// Strict equality assertions (enforces order, exact structure)
public JsonContentAssert isStrictlyEqualToJson(CharSequence expected);
public JsonContentAssert isStrictlyEqualToJson(byte[] expected);
public JsonContentAssert isStrictlyEqualToJson(File expected);
// JSON path existence assertions
public JsonContentAssert hasJsonPath(CharSequence expression, Object... args);
public JsonContentAssert hasJsonPathValue(CharSequence expression, Object... args);
public JsonContentAssert doesNotHaveJsonPath(CharSequence expression, Object... args);
// JSON path type assertions
public JsonContentAssert hasJsonPathStringValue(CharSequence expression, Object... args);
public JsonContentAssert hasJsonPathNumberValue(CharSequence expression, Object... args);
public JsonContentAssert hasJsonPathBooleanValue(CharSequence expression, Object... args);
public JsonContentAssert hasJsonPathArrayValue(CharSequence expression, Object... args);
public JsonContentAssert hasJsonPathMapValue(CharSequence expression, Object... args);
// JSON path value extraction (returns typed assertions for chaining)
public AbstractObjectAssert<?, Object> extractingJsonPathValue(CharSequence expression, Object... args);
public AbstractCharSequenceAssert<?, String> extractingJsonPathStringValue(CharSequence expression, Object... args);
public AbstractObjectAssert<?, Number> extractingJsonPathNumberValue(CharSequence expression, Object... args);
public AbstractBooleanAssert<?> extractingJsonPathBooleanValue(CharSequence expression, Object... args);
public <E> ListAssert<E> extractingJsonPathArrayValue(CharSequence expression, Object... args);
public <K, V> MapAssert<K, V> extractingJsonPathMapValue(CharSequence expression, Object... args);
}
// Example chained assertions:
assertThat(jsonContent)
.hasJsonPath("$.users[*].name")
.hasJsonPathArrayValue("$.users")
.extractingJsonPathStringValue("$.users[0].email")
.startsWith("user")
.endsWith("@example.com");Rich assertions for validating application contexts, beans, and context startup failures with fluent AssertJ API.
Key Interfaces:
AssertableApplicationContext - Context with assertions (since 2.0.0)ApplicationContextAssert<C> - Context assertion methods (since 2.0.0)AssertableWebApplicationContext - Web context assertions (since 2.0.0)AssertableReactiveWebApplicationContext - Reactive context assertions (since 2.0.0)When to Use: Asserting on beans, context state, startup failures in context runner tests
Package: org.springframework.boot.test.context.assertj
// Example usage with context runners:
new ApplicationContextRunner()
.withUserConfiguration(DataSourceConfig.class)
.run(context -> {
assertThat(context).hasSingleBean(DataSource.class);
assertThat(context).hasBean("dataSource");
assertThat(context).getBean(DataSource.class)
.isInstanceOf(HikariDataSource.class);
assertThat(context).getBeans(DataSource.class)
.hasSize(1)
.containsKey("dataSource");
});
// Example testing for context failure:
new ApplicationContextRunner()
.withUserConfiguration(InvalidConfig.class)
.run(context -> {
assertThat(context).hasFailed();
assertThat(context).getFailure()
.isInstanceOf(BeanCreationException.class)
.hasMessageContaining("Could not create bean");
});
/**
* ApplicationContext that can be used with AssertJ assertions
* @since 2.0.0
*/
public interface AssertableApplicationContext extends ConfigurableApplicationContext, AssertProvider<ApplicationContextAssert<ApplicationContext>> {
/**
* Return AssertJ assertions for this context
* @return ApplicationContextAssert instance
*/
ApplicationContextAssert<ApplicationContext> assertThat();
/**
* Get the startup failure if the context failed to load
* @return the startup failure or null if context started successfully
*/
Throwable getStartupFailure();
}
/**
* AssertJ assertions for ApplicationContext
* @param <C> the application context type
* @since 2.0.0
*/
public class ApplicationContextAssert<C extends ApplicationContext> extends AbstractAssert<ApplicationContextAssert<C>, C> {
/**
* Verify context has a bean with the given name
* @param name the bean name
* @return this assertion object
*/
public ApplicationContextAssert<C> hasBean(String name);
/**
* Verify context has a single bean of the given type
* @param type the bean type
* @return this assertion object
*/
public ApplicationContextAssert<C> hasSingleBean(Class<?> type);
/**
* Verify context does not have a bean of the given type
* @param type the bean type
* @return this assertion object
*/
public ApplicationContextAssert<C> doesNotHaveBean(Class<?> type);
/**
* Verify context does not have a bean with the given name
* @param name the bean name
* @return this assertion object
*/
public ApplicationContextAssert<C> doesNotHaveBean(String name);
/**
* Extract bean for further assertions
* @param name the bean name
* @return ObjectAssert for the bean
*/
public AbstractObjectAssert<?, Object> getBean(String name);
/**
* Extract bean of specific type for further assertions
* @param type the bean type
* @param <T> the bean type
* @return ObjectAssert for the bean
*/
public <T> AbstractObjectAssert<?, T> getBean(Class<T> type);
/**
* Extract bean of specific type with name for further assertions
* @param name the bean name
* @param type the bean type
* @param <T> the bean type
* @return ObjectAssert for the bean
*/
public <T> AbstractObjectAssert<?, T> getBean(String name, Class<T> type);
/**
* Get all beans of a given type
* @param type the bean type
* @param <T> the bean type
* @return MapAssert for name to bean mappings
*/
public <T> MapAssert<String, T> getBeans(Class<T> type);
/**
* Verify context failed to start
* @return this assertion object
*/
public ApplicationContextAssert<C> hasFailed();
/**
* Extract the startup failure for further assertions
* @return ThrowableAssert for the failure
*/
public AbstractThrowableAssert<?, ? extends Throwable> getFailure();
}Capture and verify System.out and System.err output during test execution.
Key Classes:
OutputCaptureExtension - JUnit 5 extension (since 2.2.0)CapturedOutput - Interface for captured output (since 2.2.0)OutputCaptureRule - JUnit 4 rule (deprecated since 2.2.0)When to Use: Verifying logging output, console messages, error output
Package: org.springframework.boot.test.system
// Example usage:
@ExtendWith(OutputCaptureExtension.class)
class MyTest {
@Test
void captureSystemOut(CapturedOutput output) {
System.out.println("Hello World");
System.err.println("Error message");
assertThat(output.getOut()).contains("Hello World");
assertThat(output.getErr()).contains("Error message");
assertThat(output.getAll()).contains("Hello World", "Error message");
assertThat(output).contains("Hello"); // CapturedOutput is CharSequence
}
}
/**
* JUnit 5 Extension to capture System.out and System.err
* @since 2.2.0
*/
public class OutputCaptureExtension implements BeforeEachCallback, AfterEachCallback, ParameterResolver {
/**
* Resolve CapturedOutput parameter for test methods
* @param parameterContext the parameter context
* @param extensionContext the extension context
* @return true if parameter is CapturedOutput
*/
@Override
public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext);
/**
* Resolve the CapturedOutput instance
* @param parameterContext the parameter context
* @param extensionContext the extension context
* @return the CapturedOutput instance
*/
@Override
public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext);
}
/**
* Interface for accessing captured output
* @since 2.2.0
*/
public interface CapturedOutput extends CharSequence {
/**
* Get all captured output (both stdout and stderr)
* @return the complete captured output
*/
String getAll();
/**
* Get captured stdout output only
* @return stdout content
*/
String getOut();
/**
* Get captured stderr output only
* @return stderr content
*/
String getErr();
// Inherits from CharSequence:
// - int length()
// - char charAt(int index)
// - CharSequence subSequence(int start, int end)
// - String toString()
}Define test-specific bean configurations and components for focused test environments, and simulate classloading scenarios with filtered classloaders.
Key Classes:
@TestConfiguration - Test-specific configuration (since 1.4.0)@TestComponent - Test-only component (since 1.4.0)FilteredClassLoader - Test classloader for simulating missing dependencies (since 2.0.0)When to Use: Overriding beans for tests, adding test-specific beans, testing conditional auto-configurations
Package: org.springframework.boot.test.context
// Example usage as nested configuration:
@SpringBootTest
class MyIntegrationTest {
@TestConfiguration
static class TestConfig {
@Bean
@Primary
DataSource testDataSource() {
return new EmbeddedDatabaseBuilder()
.setType(EmbeddedDatabaseType.H2)
.build();
}
}
@Autowired
private DataSource dataSource; // Gets testDataSource bean
}
// Example usage as separate class:
@TestConfiguration(proxyBeanMethods = false)
public class MockServiceConfiguration {
@Bean
public ExternalService externalService() {
return Mockito.mock(ExternalService.class);
}
}
// Import in test:
@SpringBootTest
@Import(MockServiceConfiguration.class)
class ServiceTest { }
/**
* Configuration that can be imported or used as nested configuration
* Does not trigger component scanning or prevent @SpringBootConfiguration detection
* @since 1.4.0
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface TestConfiguration {
/**
* Explicitly specify the name of the Spring bean definition
* @return the bean name
*/
String value() default "";
/**
* Specify whether @Bean methods should get proxied
* @return true to use proxies (default), false for lite mode
*/
boolean proxyBeanMethods() default true;
}
/**
* Stereotyp annotation for test components
* Excluded from component scans unless explicitly included
* @since 1.4.0
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface TestComponent {
/**
* The value may indicate a suggestion for a logical component name
* @return the suggested component name, if any
*/
String value() default "";
}Utilities for managing test-specific properties, environment variables, and system properties.
Key Classes:
TestPropertyValues - Fluent property management (since 2.0.0)When to Use: Setting properties for context runner tests, temporary property override
Package: org.springframework.boot.test.util
// Example usage with context runners:
new ApplicationContextRunner()
.withInitializer(context ->
TestPropertyValues.of(
"app.name=TestApp",
"app.timeout=5000",
"app.debug=true"
).applyTo(context))
.run(context -> {
assertThat(context.getEnvironment().getProperty("app.name"))
.isEqualTo("TestApp");
});
// Example with fluent API:
TestPropertyValues.of("prop1=value1")
.and("prop2=value2", "prop3=value3")
.applyTo(context);
// Example with system properties:
String result = TestPropertyValues
.of("java.io.tmpdir=/custom/tmp")
.applyToSystemProperties(() -> {
// Code that uses system properties
return System.getProperty("java.io.tmpdir");
});
assertThat(result).isEqualTo("/custom/tmp");
/**
* Utility for managing test-specific property values
* @since 2.0.0
*/
public final class TestPropertyValues {
/**
* Create instance from name=value pairs
* @param pairs property pairs in key=value format
* @return TestPropertyValues instance
*/
public static TestPropertyValues of(String... pairs);
/**
* Create instance from a map
* @param map map of property names to values
* @return TestPropertyValues instance
*/
public static TestPropertyValues of(Map<String, String> map);
/**
* Create instance from an iterable of name=value pairs
* @param pairs iterable of property pairs
* @return TestPropertyValues instance
*/
public static TestPropertyValues of(Iterable<String> pairs);
/**
* Create empty instance
* @return empty TestPropertyValues
*/
public static TestPropertyValues empty();
/**
* Add additional property values
* @param pairs additional property pairs
* @return new TestPropertyValues with added properties
*/
public TestPropertyValues and(String... pairs);
/**
* Apply properties to an ApplicationContext
* @param context the context to configure
*/
public void applyTo(ConfigurableApplicationContext context);
/**
* Apply properties to an Environment
* @param environment the environment to configure
*/
public void applyTo(ConfigurableEnvironment environment);
/**
* Apply properties to an Environment with specific property source name
* @param environment the environment to configure
* @param name the name of the property source
*/
public void applyTo(ConfigurableEnvironment environment, TestPropertyValues.Type type, String name);
/**
* Apply properties to system properties
* @param action action to perform with system properties set
* @param <T> return type
* @return result of the action
*/
public <T> T applyToSystemProperties(Supplier<T> action);
/**
* Property source type
*/
public enum Type {
/** Map property source */
MAP,
/** System environment property source */
SYSTEM_ENVIRONMENT
}
}HtmlUnit integration, local test web server utilities, and mock servlet context support for web application testing.
Key Classes:
LocalTestWebServer - Test server information (since 4.0.0)UriBuilderFactoryWebClient - HtmlUnit client (since 4.0.0)UriBuilderFactoryWebConnectionHtmlUnitDriver - Selenium driver (since 4.0.0)SpringBootMockServletContext - Mock servlet context (since 1.4.0)When to Use: End-to-end web testing, HtmlUnit-based UI testing
Package: org.springframework.boot.test.http.server, org.springframework.boot.test.web.htmlunit, org.springframework.boot.test.mock.web
// Example usage with @SpringBootTest:
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class WebIntegrationTest {
@Autowired
private ApplicationContext context;
@Test
void testWithLocalTestWebServer() {
LocalTestWebServer server = LocalTestWebServer.obtain(context);
String baseUri = server.uri(); // "http://localhost:8080"
String apiUri = server.uri("/api/users"); // "http://localhost:8080/api/users"
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<String> response = restTemplate.getForEntity(apiUri, String.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
}
}
// Example with HtmlUnit WebClient:
LocalTestWebServer server = LocalTestWebServer.of(Scheme.HTTP, 8080);
UriBuilderFactoryWebClient client = new UriBuilderFactoryWebClient(server.uriBuilderFactory());
HtmlPage page = client.getPage("/index.html");
assertThat(page.getTitleText()).isEqualTo("Welcome");
/**
* Information about a local test web server
* @since 4.0.0
*/
public final class LocalTestWebServer {
/**
* Get the scheme (HTTP or HTTPS)
* @return the scheme
*/
public Scheme scheme();
/**
* Get the base URI for this server
* @return the base URI (e.g., "http://localhost:8080")
*/
public String uri();
/**
* Get a URI with the given path
* @param uri the path to append
* @return the complete URI
*/
public String uri(String uri);
/**
* Get a URI builder for the given path
* @param uri the path
* @return UriBuilder instance
*/
public UriBuilder uriBuilder(String uri);
/**
* Get a URI builder factory for this server
* @return UriBuilderFactory instance
*/
public UriBuilderFactory uriBuilderFactory();
/**
* Create a new LocalTestWebServer with a different path
* @param path the new path
* @return new LocalTestWebServer instance
*/
public LocalTestWebServer withPath(String path);
/**
* Create from scheme and port
* @param scheme the scheme (HTTP or HTTPS)
* @param port the port number
* @return LocalTestWebServer instance
*/
public static LocalTestWebServer of(Scheme scheme, int port);
/**
* Create from scheme, port, and context path
* @param scheme the scheme
* @param port the port number
* @param contextPath the context path
* @return LocalTestWebServer instance
*/
public static LocalTestWebServer of(Scheme scheme, int port, String contextPath);
/**
* Obtain from an ApplicationContext
* @param applicationContext the application context
* @return LocalTestWebServer instance
* @throws IllegalStateException if no local test web server is available
*/
public static LocalTestWebServer obtain(ApplicationContext applicationContext);
/**
* Get the LocalTestWebServer from an ApplicationContext
* @param applicationContext the application context
* @return LocalTestWebServer instance or null if not available
*/
public static LocalTestWebServer get(ApplicationContext applicationContext);
/**
* Create from scheme and base URI details supplier
* @param scheme the scheme
* @param baseUriDetailsSupplier supplier for base URI details
* @return LocalTestWebServer instance
*/
public static LocalTestWebServer of(Scheme scheme, Supplier<BaseUriDetails> baseUriDetailsSupplier);
/**
* Details of the base URI to the local test web server
*/
public record BaseUriDetails(int port, String path) {
/**
* Get the URI for the given scheme
* @param scheme the scheme
* @return the URI string
*/
String uri(Scheme scheme);
/**
* Create new BaseUriDetails with appended path
* @param path the path to append
* @return new BaseUriDetails instance
*/
BaseUriDetails withPath(String path);
}
/**
* Server scheme enumeration
*/
public enum Scheme {
/** HTTP scheme */
HTTP,
/** HTTPS scheme */
HTTPS
}
/**
* Internal strategy to provide the running LocalTestWebServer
* Implementations registered in spring.factories
*/
@FunctionalInterface
public interface Provider {
/**
* Return the provided LocalTestWebServer or null
* @return the local test web server or null
*/
LocalTestWebServer getLocalTestWebServer();
}
}
/**
* HtmlUnit WebClient configured with UriBuilderFactory
* @since 4.0.0
*/
public class UriBuilderFactoryWebClient extends WebClient {
/**
* Create with UriBuilderFactory
* @param uriBuilderFactory the URI builder factory
*/
public UriBuilderFactoryWebClient(UriBuilderFactory uriBuilderFactory);
/**
* Get a page using a relative URL
* @param url the relative URL
* @param <P> the page type
* @return the page
* @throws IOException on error
*/
@Override
public <P extends Page> P getPage(String url) throws IOException;
}
/**
* Mock ServletContext for Spring Boot applications
* @since 1.4.0
*/
public class SpringBootMockServletContext extends MockServletContext {
/**
* Create with resource base path
* @param resourceBasePath the base path for resources
*/
public SpringBootMockServletContext(String resourceBasePath);
/**
* Create with resource base path and resource loader
* @param resourceBasePath the base path for resources
* @param resourceLoader the resource loader
*/
public SpringBootMockServletContext(String resourceBasePath, ResourceLoader resourceLoader);
}| Scenario | Recommended Approach | Key Classes |
|---|---|---|
| Full integration test with web server | @SpringBootTest with RANDOM_PORT | SpringBootTest, LocalTestWebServer |
| Test auto-configuration in isolation | Context runners | ApplicationContextRunner |
| Test JSON serialization | JSON testers | JacksonTester, GsonTester |
| Test with minimal context | Context runners with specific config | ApplicationContextRunner.withUserConfiguration() |
| Verify logging output | Output capture | OutputCaptureExtension, CapturedOutput |
| Test-specific bean overrides | @TestConfiguration | TestConfiguration, TestComponent |
| Web UI testing with HtmlUnit | Web test utilities | UriBuilderFactoryWebClient |
| Temporary test properties | Test property values | TestPropertyValues |
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.http.server.LocalTestWebServer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.web.client.RestTemplate;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class IntegrationTest {
@Autowired
private ApplicationContext context;
@Test
void testEndpoint() {
LocalTestWebServer server = LocalTestWebServer.obtain(context);
RestTemplate restTemplate = new RestTemplate();
String response = restTemplate.getForObject(server.uri("/api/test"), String.class);
assertThat(response).isNotNull();
}
}import org.springframework.boot.test.context.runner.ApplicationContextRunner;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
class AutoConfigTest {
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
.withUserConfiguration(MyAutoConfiguration.class);
@Test
void whenConditionMet_beanIsCreated() {
contextRunner
.withPropertyValues("feature.enabled=true")
.run(context -> assertThat(context).hasSingleBean(FeatureBean.class));
}
}import org.springframework.boot.test.json.JacksonTester;
import tools.jackson.databind.json.JsonMapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
class JsonTest {
private JacksonTester<User> json;
@BeforeEach
void setup() {
JacksonTester.initFields(this, JsonMapper.builder().build());
}
@Test
void testSerialization() throws Exception {
User user = new User("john", "john@example.com");
assertThat(json.write(user))
.hasJsonPathStringValue("$.name")
.extractingJsonPathStringValue("$.email")
.isEqualTo("john@example.com");
}
}import org.springframework.boot.test.system.OutputCaptureExtension;
import org.springframework.boot.test.system.CapturedOutput;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import static org.assertj.core.api.Assertions.assertThat;
@ExtendWith(OutputCaptureExtension.class)
class OutputTest {
@Test
void testLogging(CapturedOutput output) {
System.out.println("Test message");
assertThat(output).contains("Test message");
}
}Spring Boot 4.0 introduces Jackson 3 support while deprecating Jackson 2 APIs.
Tester Class Migration:
// Old (Spring Boot 3.x with Jackson 2)
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.test.json.Jackson2Tester;
private Jackson2Tester<User> json;
@BeforeEach
void setup() {
ObjectMapper mapper = new ObjectMapper();
Jackson2Tester.initFields(this, mapper);
}
// New (Spring Boot 4.0 with Jackson 3)
import tools.jackson.databind.json.JsonMapper;
import org.springframework.boot.test.json.JacksonTester;
private JacksonTester<User> json;
@BeforeEach
void setup() {
JsonMapper mapper = JsonMapper.builder().build();
JacksonTester.initFields(this, mapper);
}Package Changes:
com.fasterxml.jackson.* → tools.jackson.*ObjectMapper → JsonMappercom.fasterxml.jackson.datatype.jsr310.JavaTimeModule → tools.jackson.datatype.jsr310.JavaTimeModuleConfiguration Pattern Changes:
// Old (Jackson 2)
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
// New (Jackson 3)
JsonMapper mapper = JsonMapper.builder()
.addModule(new JavaTimeModule())
.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)
.serializationInclusion(JsonInclude.Include.NON_NULL)
.build();Migration Timeline:
OutputCaptureRule (JUnit 4) deprecated - use OutputCaptureExtension (JUnit 5):
// Old (JUnit 4)
import org.junit.Rule;
import org.springframework.boot.test.rule.OutputCaptureRule;
public class MyTest {
@Rule
public OutputCaptureRule output = new OutputCaptureRule();
@Test
public void test() {
System.out.println("message");
assertThat(output.toString()).contains("message");
}
}
// New (JUnit 5)
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.boot.test.system.OutputCaptureExtension;
import org.springframework.boot.test.system.CapturedOutput;
@ExtendWith(OutputCaptureExtension.class)
class MyTest {
@Test
void test(CapturedOutput output) {
System.out.println("message");
assertThat(output).contains("message");
}
}See Integration Testing for detailed usage.
Issue: NoSuchBeanDefinitionException in @SpringBootTest
Issue: Context runner test fails to load expected beans
Issue: JSON tester fields are null
initFields() in @BeforeEachJacksonTester.initFields(this, mapper) in setup methodIssue: Output capture doesn't capture logs
Issue: Random port not injected
webEnvironment = WebEnvironment.RANDOM_PORT