Spring Boot Testing
Spring Boot 通过 spring-boot-starter-test 提供全面的测试支持,内置 JUnit 5、Mockito、AssertJ 等工具。
测试类型速查
| 注解 | 用途 | 加载范围 |
|---|---|---|
@SpringBootTest | 集成测试 | 完整上下文 |
@WebMvcTest | 切片测试 | 仅 MVC 组件 |
@DataJpaTest | 切片测试 | 仅 JPA 组件 |
@WebFluxTest | 切片测试 | 仅 WebFlux 组件 |
@JsonTest | 切片测试 | JSON 序列化 |
@RestClientTest | 切片测试 | RestTemplate/RestClient |
Maven 依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>集成测试
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
class MyIntegrationTests {
@Autowired
private TestRestTemplate template;
@Test
void testExample() {
String result = template.getForObject("/hello", String.class);
assertThat(result).isEqualTo("Hello");
}
}| webEnvironment 值 | 说明 |
|---|---|
MOCK | 默认,加载 MOCK Web 环境 |
RANDOM_PORT | 启动随机端口的嵌入式服务器 |
DEFINED_PORT | 使用配置的端口 |
NONE | 不启动 Web 环境 |
Mock 测试
@SpringBootTest
class MyTests {
@MockitoBean
private UserService userService;
@Autowired
private UserController userController;
@Test
void testExample() {
given(this.userService.getUser()).willReturn(new User("张三"));
User result = userController.getUser();
assertThat(result.getName()).isEqualTo("张三");
}
}提示
Spring Boot 3.4+ 推荐使用 @MockitoBean 替代已废弃的 @MockBean。
切片测试
@WebMvcTest
只加载 Controller 层,用 @MockitoBean 模拟 Service 依赖:
@WebMvcTest(UserController.class)
class MyControllerTests {
@Autowired
private MockMvcTester mvc;
@MockitoBean
private UserService userService;
@Test
void testExample() {
given(this.userService.getUser()).willReturn(new User("张三"));
assertThat(this.mvc.get().uri("/users/1"))
.hasStatusOk()
.hasBodyTextEqualTo("张三");
}
}@DataJpaTest
只加载 JPA 组件,默认使用嵌入式数据库,事务自动回滚:
@DataJpaTest
class MyRepositoryTests {
@Autowired
private TestEntityManager entityManager;
@Autowired
private UserRepository repository;
@Test
void testExample() {
entityManager.persist(new User("张三", "zhangsan@example.com"));
User user = repository.findByUsername("张三");
assertThat(user.getEmail()).isEqualTo("zhangsan@example.com");
}
}@DataJpaTest 使用真实数据库
@DataJpaTest
@AutoConfigureTestDatabase(replace = Replace.NONE)
class MyRepositoryTests { }MockMvc 使用
传统方式
@SpringBootTest
@AutoConfigureMockMvc
class MyMockMvcTests {
@Autowired
private MockMvc mvc;
@Test
void testWithMockMvc() throws Exception {
mvc.perform(get("/hello"))
.andExpect(status().isOk())
.andExpect(content().string("Hello World"));
}
}AssertJ 风格(MockMvcTester)
@SpringBootTest
@AutoConfigureMockMvc
class MyMockMvcTests {
@Autowired
private MockMvcTester mvc;
@Test
void testWithMockMvcTester() {
assertThat(mvc.get().uri("/hello"))
.hasStatusOk()
.hasBodyTextEqualTo("Hello World");
}
}AssertJ 断言
import static org.assertj.core.api.Assertions.assertThat;
assertThat(user.getUsername()).isEqualTo("sboot");
assertThat(users).hasSize(3).contains("boot");
assertThat(Optional.of("boot")).isPresent().contains("boot");
assertThatThrownBy(() -> userService.getUser(null))
.isInstanceOf(IllegalArgumentException.class)
.hasMessage("id 不能为空");测试配置
@TestConfiguration
定义仅用于测试的 Bean:
@TestConfiguration
static class MyTestConfiguration {
@Bean
RestTemplateBuilder restTemplateBuilder() {
return new RestTemplateBuilder()
.connectTimeout(Duration.ofSeconds(1))
.readTimeout(Duration.ofSeconds(1));
}
}
@SpringBootTest
@Import(MyTestConfiguration.class)
class MyTests { }常见问题
| 问题 | 原因 | 解决方案 |
|---|---|---|
| 上下文加载失败 | 注解配置或包路径错误 | 检查 @SpringBootTest 配置和测试类包路径 |
| MockBean 不生效 | 注解位置或测试类型不匹配 | 确认注解在正确字段,使用正确的测试注解 |
| 切片测试缺少组件 | 只加载特定组件 | 使用 @MockitoBean 模拟缺失的依赖 |