spring-projects/spring-framework
Testing support
Active contributors: Sam Brannen, Juergen Hoeller, rstoyanchev
Spring Framework ships first-class testing infrastructure in spring-test. This page covers the high-level testing capabilities available to applications: the TestContext framework, MockMvc, WebTestClient, mocks for Servlet and reactive APIs, and helpers for transactions and SQL.
TestContext framework
The TestContext framework provides per-class ApplicationContext setup with caching. Two tests with the same configuration share a single context.
@SpringJUnitConfig(MyAppConfig.class)
class UserServiceTests {
@Autowired UserService userService;
@Test
void findById_returnsUser() {
assertThat(userService.findById(42L)).isPresent();
}
}@SpringJUnitConfig is a meta-annotation combining @ExtendWith(SpringExtension.class) and @ContextConfiguration. The SpringExtension (JUnit 5) drives TestContextManager, which loads or fetches the cached context, autowires the test instance, and notifies test execution listeners.
Context caching
Contexts are cached by configuration key — the set of @ContextConfiguration parameters, profiles, property sources, etc. Changing any of these keys produces a new cache entry. The default cache size is 32 (spring.test.context.cache.maxSize), with LRU eviction.
This is the single most important performance feature of the framework. Without caching, every test method would pay the full context startup cost.
@DirtiesContext
If a test mutates the context (replaces a bean, changes the Environment), apply @DirtiesContext to evict the cache entry. Use sparingly — context startup is expensive.
Transactional tests
@SpringJUnitConfig(...)
@Transactional
class UserRepositoryTests { ... }Tests annotated @Transactional (or under a @Transactional test class) run inside a transaction that rolls back at the end. Database state is unchanged between tests. To commit instead, use @Commit or @Rollback(false).
@Sql
@Test
@Sql("/schema.sql")
@Sql("/data.sql")
void testUserLookup() { ... }@Sql runs SQL scripts before (or after) a test method. Scripts are loaded from the classpath and run via ScriptUtils against the configured DataSource.
MockMvc
MockMvc exercises Spring MVC controllers without starting a Servlet container. It's the recommended way to test MVC controllers.
@SpringJUnitConfig
@WebAppConfiguration
class UserControllerTests {
@Autowired WebApplicationContext wac;
MockMvc mvc;
@BeforeEach
void setup() {
mvc = MockMvcBuilders.webAppContextSetup(wac).build();
}
@Test
void getUser() throws Exception {
mvc.perform(get("/users/42").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$.id").value(42));
}
}The MockMvc builder offers two modes:
- Standalone — Configure controllers, resolvers, and converters manually. Fastest, but you must wire what you want.
- WebAppContext — Boot a full
WebApplicationContext. Slower per test class, but realistic.
In Spring Boot, @WebMvcTest provides a slice of the context with just MVC infrastructure and your specified controllers — fast, focused tests.
Result matchers
MockMvcResultMatchers (status(), content(), jsonPath(), header(), redirectedUrl(), …) provide fluent assertions over the response.
MockMvcWebTestClient
A bridge that exposes a WebTestClient API over MockMvc — so the same test code works for both stacks.
WebTestClient
WebTestClient is the reactive equivalent of MockMvc plus an HTTP-connected mode.
WebTestClient client = WebTestClient
.bindToApplicationContext(context)
.build();
client.get().uri("/users/42")
.accept(MediaType.APPLICATION_JSON)
.exchange()
.expectStatus().isOk()
.expectBody()
.jsonPath("$.id").isEqualTo(42);Modes:
| Mode | Network? | Use case |
|---|---|---|
bindToApplicationContext |
No | WebFlux equivalent of MockMvc |
bindToRouterFunction |
No | Test functional endpoints in isolation |
bindToController |
No | Test single annotated controllers |
bindToServer().baseUrl(...) |
Yes | Test against a running server |
Mocks
spring-test provides drop-in mocks for both web stacks' runtime APIs:
| Mock | Replaces |
|---|---|
MockHttpServletRequest |
HttpServletRequest |
MockHttpServletResponse |
HttpServletResponse |
MockHttpSession |
HttpSession |
MockServletContext |
ServletContext |
MockServerHttpRequest |
ServerHttpRequest (reactive) |
MockServerHttpResponse |
ServerHttpResponse (reactive) |
MockServerWebExchange |
ServerWebExchange (reactive) |
MockEnvironment |
Environment |
These are useful for testing filters, interceptors, or any code that takes the runtime types directly.
@MockitoBean
Replaces a bean in the application context with a Mockito mock for the duration of a test:
@SpringJUnitConfig
class ServiceTests {
@MockitoBean UserRepository repo;
@Autowired UserService service;
@Test
void test() {
when(repo.findById(any())).thenReturn(Optional.of(new User(...)));
assertThat(service.findById(42L)).isPresent();
}
}The bean replacement keys into the context cache differently from @DirtiesContext — Spring computes a separate cache key including the mocked beans, so reuse is still possible.
MockRestServiceServer
Records and asserts RestTemplate / RestClient interactions without a real HTTP server:
MockRestServiceServer server = MockRestServiceServer.createServer(restClient);
server.expect(once(), requestTo("/users/42"))
.andRespond(withSuccess("{\"id\":42}", APPLICATION_JSON));For WebClient, use the same approach with MockWebServer (from OkHttp) or WireMock. The framework doesn't ship a WebClient-specific mock server.
TestExecutionListeners
TestExecutionListener is the SPI for hooking into test lifecycle. Built-in listeners power @DirtiesContext, @Transactional, @Sql, @MockitoBean, and event recording (@RecordApplicationEvents). To add your own, implement the interface and register via @TestExecutionListeners or META-INF/spring.factories.
See also
- spring-test — module reference
- how-to-contribute/testing — practical guidance for contributors to the framework
- web-mvc and reactive-stack — what
MockMvc/WebTestClienttest
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.