Skip to content

Spring Test Context and Slices

Spring Test provides a spectrum of test contexts, from a targeted slice to the full application. This page maps the spectrum as the samples use it: SpringJUnitConfig for plain Spring modules, @SpringBootTest for full Boot contexts, and the Boot test slices that load only what a layer needs.

SpringJUnitConfig: plain Spring without Boot

Non-Boot samples test with SpringJUnitConfig — the JUnit 5 extension that builds an ApplicationContext from the given configuration classes without any Boot machinery:

@SpringJUnitConfig(classes = Application.class)
@ActiveProfiles("test")   // disables the Netty @Profile("default") server bean
public class ApplicationTests {

    @Autowired
    ApplicationContext context;

    WebTestClient rest;

    @BeforeEach
    public void setup() {
        this.rest = WebTestClient
                .bindToApplicationContext(this.context)
                .configureClient()
                .build();
    }

    @Test
    public void getAllPostsWillBeOk() {
        this.rest
                .get()
                .uri("/posts")
                .exchange()
                .expectStatus().isOk();
    }
}

This pattern runs across the plain Spring samples — the integration sample's ApplicationTests and PostControllerTest show it with bindToApplicationContext and the narrower bindToController:

this.rest = WebTestClient.bindToController(this.ctrl)
        .configureClient()
        .build();

SpringBootTest: the full context

@SpringBootTest boots the complete application. With WebEnvironment.RANDOM_PORT it starts the real server on a free port, and @AutoConfigureWebTestClient injects a client ready to talk to it:

@AutoConfigureWebTestClient
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class IntegrationTests {

    @Autowired
    WebTestClient client;

    @Test
    public void getAllPosts() {
        client.get().uri("/posts")
                .exchange()
                .expectStatus().isOk()
                .expectBody().jsonPath("$.size()").isEqualTo(2);
    }
}

Combine it with the Testcontainers styles from Data Operations with Testcontainers (@ServiceConnection or @DynamicPropertySource) and the full stack — web layer, data layer, real database — runs in one test.

Integration tests over a real server

Some contracts only exist over the wire. The integration sample binds its own Reactor Netty server bean and a server-bound WebTestClient:

@SpringJUnitConfig(classes = Application.class)
public class IntegrationTests {

    @Autowired
    HttpServer httpServer;

    private DisposableServer disposableServer;

    @BeforeEach
    public void setup() {
        this.disposableServer = this.httpServer.bindNow();
        this.client = WebTestClient
                .bindToServer()
                .responseTimeout(Duration.ofMillis(5000))
                .baseUrl("http://localhost:" + this.port)
                .build();
    }

    @AfterEach
    public void tearDown() {
        this.disposableServer.disposeNow();
    }

    @Test
    public void getAllPostsWillBeOk_viaIntegration() {
        this.client
                .get()
                .uri("/all")
                .exchange()
                .expectStatus().isOk();
    }
}

This is the shape to use for SSE streams, WebSocket handshakes, and cookie/header contracts — see session-header for a worked example.

Test slices

Boot's test slices load only the auto-configuration a layer needs, keeping tests fast and focused:

Slice Loads Typical use
@WebFluxTest WebFlux infrastructure for the given controllers Controller and filter tests with mocked dependencies — see Testing Web Components
@JsonTest JSON serializers/deserializers only (Jackson, and @JsonTester injection) Round-trip serialization assertions without any web layer
@DataMongoTest Spring Data Mongo repositories and ReactiveMongoTemplate Repository tests against a real Mongo — pair with Testcontainers
@DataR2dbcTest Spring Data R2DBC repositories, DatabaseClient R2DBC repository tests
@DataNeo4jTest Spring Data Neo4j repositories Neo4j repository tests — see Neo4j — Testing

A @DataMongoTest repository test from the boot-data-mongo sample — the slice plus a @ServiceConnection container gives a complete database test with no web layer loaded:

@DataMongoTest
@Import(TestcontainersConfiguration.class)
@ActiveProfiles("test")
public class PostRepositoryTest {

    @Autowired
    ReactiveMongoTemplate reactiveMongoTemplate;

    @Autowired
    PostRepository postRepository;
}

Slices and transactions

Reactive slices are not transactional by default. When a slice (for example @DataNeo4jTest) applies test-managed transactions that the reactive stack cannot drive, add @Transactional(propagation = Propagation.NEVER) — the Neo4j — Testing page walks through the details.

A @JsonTest follows the same recipe — the slice auto-configures the JSON beans and injects a tester:

@JsonTest
class PostJsonTest {

    @Autowired
    JacksonTester<Post> json;

    @Test
    void serialize() throws Exception {
        var post = new Post(UUID.randomUUID(), "test title", "content");
        assertThat(json.write(post)).extractingJsonPathStringValue("$.title").isEqualTo("test title");
    }
}

The slices pair naturally with the bean-override annotations: @WebFluxTest + @MockitoBean for the web layer, data slices + Testcontainers for the persistence layer.