or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

assertj-integration.mdcontext-runners.mdindex.mdintegration-testing.mdjson-testing.mdoutput-capture.mdtest-configuration.mdtest-properties.mdweb-test-utilities.md
tile.json

index.mddocs/

Spring Boot Test

Spring 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.

Package Information

  • Package Name: org.springframework.boot:spring-boot-test
  • Package Type: Maven (Gradle)
  • Language: Java
  • Version: 4.0.0
  • Base Package: org.springframework.boot.test

Installation

Maven:

<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'

Prerequisites

  • JUnit 5 (Jupiter): Required for most testing features
  • AssertJ: Required for assertions (provided transitively)
  • Spring Framework 6.2+: Core Spring testing support
  • Java 17+: Minimum Java version

Core Package Structure

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

Core Imports

// 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;

Basic Usage

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");
    }
}

Feature Overview

Integration Testing

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
    }
}

Context Runners

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);
}

JSON Testing

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");

AssertJ Integration

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();
}

Output Capture

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()
}

Test Configuration

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 "";
}

Test Property Management

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
    }
}

Web Test Utilities

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);
}

Quick Reference: Choosing the Right Testing Approach

ScenarioRecommended ApproachKey Classes
Full integration test with web server@SpringBootTest with RANDOM_PORTSpringBootTest, LocalTestWebServer
Test auto-configuration in isolationContext runnersApplicationContextRunner
Test JSON serializationJSON testersJacksonTester, GsonTester
Test with minimal contextContext runners with specific configApplicationContextRunner.withUserConfiguration()
Verify logging outputOutput captureOutputCaptureExtension, CapturedOutput
Test-specific bean overrides@TestConfigurationTestConfiguration, TestComponent
Web UI testing with HtmlUnitWeb test utilitiesUriBuilderFactoryWebClient
Temporary test propertiesTest property valuesTestPropertyValues

Common Patterns

Pattern 1: Integration Test with Random Port

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();
    }
}

Pattern 2: Context Runner for Auto-Configuration Testing

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));
    }
}

Pattern 3: JSON Testing

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");
    }
}

Pattern 4: Output Capture

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");
    }
}

Migration Notes

From Spring Boot 3.x to 4.0

Jackson 3 Migration (Critical)

Spring Boot 4.0 introduces Jackson 3 support while deprecating Jackson 2 APIs.

  1. 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);
    }
  2. Package Changes:

    • com.fasterxml.jackson.*tools.jackson.*
    • ObjectMapperJsonMapper
    • Module paths change: com.fasterxml.jackson.datatype.jsr310.JavaTimeModuletools.jackson.datatype.jsr310.JavaTimeModule
  3. Configuration 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();
  4. Migration Timeline:

    • Spring Boot 4.0 (current): Jackson2Tester deprecated
    • Spring Boot 4.2 (planned): Jackson2Tester removed
    • Recommendation: Migrate immediately to avoid breaking changes

JUnit 4 to JUnit 5 Migration

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");
    }
}

New Annotations in 4.0

  1. @PropertyMapping: Map test annotation attributes to environment properties
  2. @TypeExcludeFilters: Register TypeExcludeFilter classes for component scanning control

See Integration Testing for detailed usage.

Troubleshooting

Common Issues

Issue: NoSuchBeanDefinitionException in @SpringBootTest

  • Cause: Missing @SpringBootApplication or component scan configuration
  • Solution: Ensure test class is in same package or subpackage as @SpringBootApplication

Issue: Context runner test fails to load expected beans

  • Cause: Missing auto-configuration in withUserConfiguration()
  • Solution: Include all required configuration classes explicitly

Issue: JSON tester fields are null

  • Cause: Forgot to call initFields() in @BeforeEach
  • Solution: Add JacksonTester.initFields(this, mapper) in setup method

Issue: Output capture doesn't capture logs

  • Cause: Logging framework configuration redirects output
  • Solution: Ensure logging outputs to System.out/System.err

Issue: Random port not injected

  • Cause: Wrong WebEnvironment mode
  • Solution: Use webEnvironment = WebEnvironment.RANDOM_PORT

See Also

Version History

  • 4.0.0: Jackson 3 support, JUnit 4 deprecation, new annotations
  • 3.x: Previous stable version with Jackson 2