Spring Boot Testing
Overview of the most important annotations and types for testing Spring Boot applications.
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:
- Spring Framework: Testing
- Spring Boot: Testing
- Philip Riecks: Testing Spring Boot Applications Made Simple
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:
- Spring Boot: Auto-configured Tests
- Spring Boot: Test Auto-configuration Annotations
- Philip Riecks: Spring Boot Test Slices: Overview and Usage
@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:
- JavaDoc: @SpringBootTest
- Spring Boot: Testing Spring Boot Applications
- Philip Riecks: Guide to @SpringBootTest for Spring Boot Integration Tests
@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 @MockitoBean to mock required beans (e.g., @Service beans from the service layer) that are not initialized in this test slice.
See:
- JavaDoc: @WebMvcTest
- Spring Boot: Auto-configured Spring MVC Tests
- Philip Riecks: Testing Spring Boot Applications With MockMvc and @WebMvcTest
@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:
- JavaDoc: @DataJpaTest
- Spring Boot: Auto-configured Data JPA Tests
- Philip Riecks: Spring Data JPA Persistence Layer Tests With @DataJpaTest
@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:
- JavaDoc: @RestClientTest
- Spring Boot: Auto-configured REST Clients
- Philip Riecks: Testing the Spring RestTemplate With @RestClientTest
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:
- JavaDoc: MockMvc
- Spring Framework: MockMvc
- Philip Riecks: Choosing Between MockMvc and @SpringBootTest for Controller Testing
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:
- JavaDoc: WebTestClient
- Spring Framework: WebTestClient
- Philip Riecks: Spring WebTestClient for Efficient REST API Testing
- Philip Riecks: Test Your Spring MVC Controller with the WebTestClient and MockMvc
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:
@MockitoBean
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.
Replacement for the deprecated @MockBean.
See:
@MockBean
Has been deprecated with Spring 3.4. Use @MockitoBean instead.
See:
@MockitoSpyBean
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.
Replacement for the deprecated @SpyBean.
See:
@SpyBean
Has been deprecated with Spring 3.4. Use @MockitoSpyBean instead.
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: