Overview of the most important annotations and types for testing Spring Boot applications.

Photo by Hannes Köttner, https://unsplash.com/de/fotos/nahaufnahme-einer-lupe-auf-einem-tisch-f9wP_rJ_cL8

When testing a Spring Boot application, you can speed up your work by reusing utilities provided directly by Spring, or by other libraries and frameworks. At the same time, the large amount of partly overlapping tools might confuse you, and make it hard to choose the right thing for the current job.

This article provides a quick overview of the most important utilities for testing Spring Boot applications. It presumes some basic knowledge in the area, as it doesn’t include detailed explanations. For more information, please refer to the links given at the specific locations inside the article. In general, I recommend the following sources for diving deeper into Spring Boot testing:

Table of Contents

Test Slices

By applying one of the following annotations to your test class, you can control which types of beans will be made available in Spring’s application context. In large applications, reducing the number of initialized beans can significantly improve the performance of your tests. However, this also requires you to focus your tests on specific parts of the application (as opposed to more comprehensive end-to-end tests).

See:

@SpringBootTest

This is the most comprehensive test annotation, which loads all types of beans into the application context. Very convenient, but might take longer to initialize.

By default, the servlet environment will be mocked, which means that a full web server will not be started (and no port opened for accepting incoming requests). This can be changed through the webEnvironment attribute of the annotation.

If an in-memory test database shall be used instead of the one from the regular configuration, you can do so with the @AutoConfigureTestDatabase annotation.

See:

@WebMvcTest

Only initializes beans that belong to the web layer, such as @Controller, @ControllerAdvice, and Filter.

Mocks the servlet environment (i.e., no web server, no port), which can be accessed via MockMvc. You can use @MockBean to mock required beans (e.g., @Service beans from the service layer) that are not initialized in this test slice.

See:

@DataJpaTest

Only initializes JPA components, such as @Entity and Spring Data JPA repositories.

Tries to use an in-memory database by default, which can be configured with @AutoConfigureTestDatabase.

See:

@DataJdbcTest

Only initializes Spring Data JDBC components, such as Spring Data JDBC repositories, DataSource, and JdbcTemplate.

Tries to use an in-memory database by default, which can be configured with @AutoConfigureTestDatabase.

See:

@JdbcTest

Only initializes JDBC components, such as DataSource and JdbcTemplate (i.e., a subset of what @DataJdbcTest does).

Tries to use an in-memory database by default, which can be configured with @AutoConfigureTestDatabase.

See:

@RestClientTest

Only initializes components that are relevant for testing REST clients built via RestTemplateBuilder or RestClient.Builder, including support for Jackson, GSON, Jsonb, MockRestServiceServer.

See:

Configuration and Properties

@ActiveProfiles

Can be used to enable certain Spring Boot profiles in your test, so that only those components, configurations and properties are being picked up that correspond to these profiles.

See:

@TestConfiguration

A @Configuration class for adding test-specific beans to the application context. Can be defined directly as a static class inside your test class, or as a separate class. In the latter case, it does not automatically become active, but has to be explicitly referenced via @Import.

This annotation is itself annotated with @TestComponent, which is not meant to be used directly.

See:

@TestPropertySource

Allows the definition of test properties directly inside the annotation, or inside referenced property files.

See:

@DynamicPropertySource

Allows a method to dynamically add test properties.

See:

@DirtiesContext

Can be applied to a test that modifies the application context (e.g., one that changes the state of a singleton bean). This way, a new application context will be created for the next test, so that it is not affected by the previous modification.

Use with care, as the creation of a new application context might take some time (depending on the size of the application).

See:

Performing Requests

There are various ways for performing requests against the application under test, each with their own pros and cons.

See:

MockMvc

Can be injected into your test for performing requests against a mocked web environment (i.e., in combination with @WebMvcTest, and with @SpringBootTest using the default WebEnvironment.MOCK).

Injection of this class is enabled through the annotation @AutoConfigureMockMvc, which is implicit part of @WebMvcTest (but not of @SpringBootTest, so you would have to add it explicitly in this case).

See:

TestRestTemplate

Inside a @SpringBootTest with a real servlet environment (i.e., WebEnvironment.DEFINED_PORT or WebEnvironment.RANDOM_PORT), a TestRestTemplate can be injected and used for sending REST requests to the application. It is very similar to RestTemplate, but has certain convenience features that are suitable for tests. For instance, it doesn’t throw exceptions when the server responds with 4xx or 5xx status codes, which makes assertions on them a bit easier.

Like RestTemplate, the TestRestTemplate can be customized through a RestTemplateBuilder @Bean.

See:

WebTestClient

Inside a @SpringBootTest with a real servlet environment (i.e., WebEnvironment.DEFINED_PORT or WebEnvironment.RANDOM_PORT), a WebTestClient can be injected and used for sending REST requests to the application. It is very similar to WebClient, but has certain convenience features that are suitable for tests. For instance, it provides a fluent API for performing assertions on the server responses.

It can also be used for testing inside a mocked servlet environment. In this case, you have to create the WebTestClient via one of the static methods “bindTo*” methods of MockMvcWebTestClient.

See:

RestClient

Can be used (since Spring Boot 3.2 / Spring Framework 6.1) for sending REST requests to a non-mocked web environment in both production and testing code. It is based on RestTemplate, and offers a fluent API (like WebClient, but without requiring the spring-boot-starter-webflux dependency).

See:

HTTP Interfaces

Instead of manually assembling requests and parsing responses, you can define or generate an HTTP interface for your service, and use it together with RestTemplate, WebClient, or RestClient for performing convenient, type-safe backend invocations.

See:

Mocks, Spies & Test Backends

@Mock

Creates a mock implementation for the annotated field, whose behavior can be controlled via Mockito (e.g., when / thenReturn).

See:

@Spy

Wraps the annotated field with spy, which can be used for verifying interactions and partial mocking.

See:

@InjectMocks

Creates a new instance of the annotated field, and tries to inject mocks into this instance using @Mock or @Spy fields from the current test.

See:

@MockBean

Creates a mock implementation for the annotated Spring bean. In contrast to a plain @Mock, this annotation makes the mock available to Spring’s application context, which means that the mock gets injected instead of the original Spring bean.

See:

@SpyBean

Wraps the annotated Spring bean with a spy. In contrast to a plain @Spy, this annotation makes the spy available to Spring’s application context, which means that the spy gets injected instead of the original, unwrapped Spring bean.

See:

MockRestServiceServer

Enables mocking backend REST services.

Can be injected into your test by applying @AutoConfigureMockRestServiceServer on the test class, but only if the REST client is constructed via RestTemplateBuilder or RestClient.Builder. This auto-configuration happens implicitly inside a @RestClientTest.

As an alternative to injecting an auto-configured MockRestServiceServer, you can create it manually by binding it to a RestTemplate.

For more comprehensive (but slower) tests, use Wiremock instead.

See:

WireMock

Replaces the real backend with a mocked one for testing.

Using WireMock instead of MockRestServiceServer has the advantage that real HTTP requests are sent “over the wire”, which means that the application layers responsible for communication via the network are also covered by the tests. The downside is that the tests are a bit slower, because they need to start up a real web server for hosting the mocked backend.

See:

Testcontainers

Starts up Docker containers for hosting backends or databases required by the application under test.

Using Testcontainers instead of an in-memory database has the advantage that the tests can use the same database technology as in production. The downside is that the tests are a bit slower, because they need to start up a local Docker container first.

See:

Other

CapturedOutput

Can be injected into a test for accessing messages that have been written to System.out and System.err. Requires your test to be annotated with @ExtendWith(OutputCaptureExtension.class).

See:

@AutoConfigureTestDatabase

Can be used to decide whether an (in-memory) test database shall be used instead of the “real” one. This annotation is implicit part of @DataJpaTest, @DataJdbcTest, and @JdbcTest. To use a real database in these types of tests, you can explicitly provide this annotation with the attribute replace = Replace.NONE.

See: