Documentation Index
Fetch the complete documentation index at: https://mintlify.com/spring-projects/spring-boot/llms.txt
Use this file to discover all available pages before exploring further.
Spring Boot ships a rich testing toolkit that covers everything from fast unit tests to full integration tests with real infrastructure. This guide covers the most common testing tasks, including running tests from the command line, isolating test configuration, using Testcontainers for zero-config database setup, and controlling test execution order.
Run tests with Maven and Gradle
Run all tests in the project:Run tests in a specific class:./mvnw test -Dtest=MyIntegrationTests
Run a single test method:./mvnw test -Dtest=MyIntegrationTests#shouldReturnUser
Skip tests during a package build:./mvnw package -DskipTests
Run all tests:Run tests in a specific class:./gradlew test --tests "com.example.MyIntegrationTests"
Run a single test method:./gradlew test --tests "com.example.MyIntegrationTests.shouldReturnUser"
Skip tests:
Use @TestPropertySource to supply test-specific values without modifying application.properties. The annotation accepts inline properties or a path to a separate .properties file.
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.TestPropertySource;
@SpringBootTest
@TestPropertySource(properties = {
"spring.datasource.url=jdbc:h2:mem:testdb",
"myapp.feature.enabled=true"
})
class MyIntegrationTests {
@Test
void contextLoads() {
}
}
To load properties from a file:
@TestPropertySource(locations = "classpath:test-overrides.properties")
For @SpringBootTest you can also pass properties directly via the annotation’s properties attribute, which behaves identically to @TestPropertySource(properties = ...) for simple cases.
Use @DirtiesContext to reset the application context
By default, Spring caches the ApplicationContext across tests for efficiency. If a test modifies shared state (database records, singleton beans, static fields), annotate it with @DirtiesContext to force a fresh context for subsequent tests.
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.annotation.DirtiesContext;
@SpringBootTest
@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
class MyStatefulTests {
@Test
void firstTest() {
// modifies shared state
}
@Test
void secondTest() {
// runs with a fresh context
}
}
Using @DirtiesContext frequently is expensive because creating a new ApplicationContext is slow. Prefer test isolation through database transactions (use @Transactional on your test class to roll back after each test) or by scoping state to the test method itself.
Set up databases with Testcontainers and @ServiceConnection
@ServiceConnection eliminates manual connection property configuration. Annotate a container field with @ServiceConnection and Spring Boot automatically creates the matching ConnectionDetails bean, overriding any spring.datasource.* or equivalent properties.
Add the Testcontainers dependencies
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-testcontainers</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>postgresql</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testcontainers</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
Declare the container as a Spring bean
Declare the container in a @TestConfiguration class so Spring manages its lifecycle. Spring starts the container before any bean that depends on it and stops it after the application context shuts down:import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.boot.testcontainers.service.connection.ServiceConnection;
import org.springframework.context.annotation.Bean;
import org.testcontainers.containers.PostgreSQLContainer;
@TestConfiguration(proxyBeanMethods = false)
class MyTestConfiguration {
@Bean
@ServiceConnection
PostgreSQLContainer<?> postgresContainer() {
return new PostgreSQLContainer<>("postgres:16");
}
}
Import the configuration in your test class
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Import;
@SpringBootTest
@Import(MyTestConfiguration.class)
class MyIntegrationTests {
@Test
void contextLoads() {
}
}
@ServiceConnection is supported for PostgreSQL, MySQL, MariaDB, MongoDB, Redis, Kafka, RabbitMQ, Elasticsearch, Neo4j, Cassandra, and many others. The full list is in the spring-boot-testcontainers module. For generic containers (those using GenericContainer), provide the image name via @ServiceConnection(name = "redis").
Mock external services with @MockBean
@MockBean adds a Mockito mock to the Spring ApplicationContext, replacing the real bean for the duration of the test. Use it to isolate your code from external HTTP services, messaging brokers, or other infrastructure.
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.BDDMockito.given;
@SpringBootTest
class MyServiceTests {
@Autowired
private MyService myService;
@MockBean
private ExternalApiClient externalApiClient;
@Test
void shouldReturnMockedData() {
given(externalApiClient.fetchData()).willReturn("mocked-response");
String result = myService.processData();
assertThat(result).isEqualTo("processed: mocked-response");
}
}
@MockBean causes the application context to be considered unique (different from contexts without the mock), so Spring will not reuse a cached context. If context startup time matters, consider using constructor injection and passing a mock directly in a plain unit test instead.
Test with Spring Security
Spring Security provides test support that lets you run a test as a specific user without going through the authentication flow:
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@SpringBootTest
@AutoConfigureMockMvc
class MySecurityTests {
@Autowired
private MockMvc mockMvc;
@Test
@WithMockUser(roles = "ADMIN")
void adminEndpointIsAccessible() throws Exception {
mockMvc.perform(get("/admin/users"))
.andExpect(status().isOk());
}
@Test
void adminEndpointRequiresAuthentication() throws Exception {
mockMvc.perform(get("/admin/users"))
.andExpect(status().isUnauthorized());
}
}
Structure @Configuration classes for slice tests
Slice tests (such as @WebMvcTest or @DataJpaTest) restrict component scanning to a limited set of bean types. Beans defined in @Configuration classes outside the scanned types are not automatically included.
Importing a large @Configuration class into a slice test loads all its beans, including ones irrelevant to the slice (for example, a DataSource bean in a @WebMvcTest). This slows down the test and can cause startup failures.
Avoid this by splitting configuration into small, focused classes:
MySecurityConfiguration.java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.web.SecurityFilterChain;
@Configuration
class MySecurityConfiguration {
@Bean
SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
// security configuration only
return http.build();
}
}
MyDatasourceConfiguration.java
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.sql.DataSource;
@Configuration
class MyDatasourceConfiguration {
@Bean
DataSource dataSource() {
// datasource configuration only
return ...;
}
}
Import only what the slice test needs:
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.context.annotation.Import;
@WebMvcTest(MyController.class)
@Import(MySecurityConfiguration.class)
class MyControllerTests {
// DataSource not loaded — test stays fast
}
Control test execution order
JUnit 5 allows you to specify the order in which test methods run within a class using @TestMethodOrder. Use this when tests share state that must be set up in sequence.
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
class MyOrderedTests {
@Test
@Order(1)
void createResource() {
}
@Test
@Order(2)
void updateResource() {
}
@Test
@Order(3)
void deleteResource() {
}
}
Test ordering is most useful for integration tests that share a single database and represent a workflow. For unit tests, prefer independent, order-agnostic tests.
Enable parallel test execution
Running tests in parallel can significantly reduce total build time on multi-core machines. Configure JUnit 5’s parallel execution in a junit-platform.properties file:
src/test/resources/junit-platform.properties
junit.jupiter.execution.parallel.enabled=true
junit.jupiter.execution.parallel.mode.default=concurrent
junit.jupiter.execution.parallel.config.strategy=dynamic
junit.jupiter.execution.parallel.config.dynamic.factor=1
For @SpringBootTest tests that share an ApplicationContext, add @Isolated to any test class that must not run concurrently with others:
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.parallel.Isolated;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
@Isolated
class MySequentialTests {
@Test
void mustNotRunConcurrently() {
}
}
Parallel execution requires that your tests are thread-safe. Tests that share mutable state (such as a database without transaction rollback) can produce flaky results when run concurrently. Validate each test class for thread safety before enabling parallel execution globally.