spring-boot-testing
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSpring Boot Testing
Spring Boot 测试
Expert guide for testing Spring Boot 4 applications with modern patterns and best practices.
采用现代模式与最佳实践的Spring Boot 4应用测试专家指南。
Core Principles
核心原则
- Test Pyramid: Unit (fast) > Slice (focused) > Integration (complete)
- Right Tool: Use the narrowest slice that gives you confidence
- AssertJ Style: Fluent, readable assertions over verbose matchers
- Modern APIs: Prefer MockMvcTester and RestTestClient over legacy alternatives
- 测试金字塔:单元测试(快速)> 切片测试(聚焦)> 集成测试(完整)
- 合适工具:使用能为你提供信心的最窄范围测试切片
- AssertJ风格:使用流畅、易读的断言替代冗长的匹配器
- 现代API:优先使用MockMvcTester和RestTestClient而非旧版替代方案
Which Test Slice?
选择哪种测试切片?
| Scenario | Annotation | Reference |
|---|---|---|
| Controller + HTTP semantics | | references/webmvctest.md |
| Repository + JPA queries | | references/datajpatest.md |
| REST client + external APIs | | references/restclienttest.md |
| JSON (de)serialization | | See references/test-slices-overview.md |
| Full application | | See references/test-slices-overview.md |
| 场景 | 注解 | 参考文档 |
|---|---|---|
| 控制器 + HTTP语义 | | references/webmvctest.md |
| 仓库 + JPA查询 | | references/datajpatest.md |
| REST客户端 + 外部API | | references/restclienttest.md |
| JSON(反)序列化 | | 参见 references/test-slices-overview.md |
| 完整应用 | | 参见 references/test-slices-overview.md |
Test Slices Reference
测试切片参考文档
- references/test-slices-overview.md - Decision matrix and comparison
- references/webmvctest.md - Web layer with MockMvc
- references/datajpatest.md - Data layer with Testcontainers
- references/restclienttest.md - REST client testing
- references/test-slices-overview.md - 决策矩阵与对比
- references/webmvctest.md - 结合MockMvc的Web层测试
- references/datajpatest.md - 结合Testcontainers的数据层测试
- references/restclienttest.md - REST客户端测试
Testing Tools Reference
测试工具参考文档
- references/mockmvc-tester.md - AssertJ-style MockMvc (recommended)
- references/mockmvc-classic.md - Traditional MockMvc
- references/resttestclient.md - Spring Boot 4+ REST client
- references/mockitobean.md - Mocking dependencies
- references/mockmvc-tester.md - 采用AssertJ风格的MockMvc(推荐)
- references/mockmvc-classic.md - 传统MockMvc
- references/resttestclient.md - Spring Boot 4+ REST客户端
- references/mockitobean.md - 依赖模拟
Assertion Libraries
断言库
- references/assertj-basics.md - Core AssertJ patterns
- references/assertj-collections.md - Collection assertions
- references/assertj-basics.md - 核心AssertJ模式
- references/assertj-collections.md - 集合断言
Testcontainers
Testcontainers
- references/testcontainers-jdbc.md - PostgreSQL, MySQL, etc.
- references/testcontainers-jdbc.md - PostgreSQL、MySQL等数据库测试
Test Data Generation
测试数据生成
- references/instancio.md - Generate complex test objects (3+ properties)
- references/instancio.md - 生成复杂测试对象(3个以上属性)
Performance & Migration
性能与迁移
- references/context-caching.md - Speed up test suites
- references/sb4-migration.md - Spring Boot 4.0 changes
- references/context-caching.md - 加速测试套件
- references/sb4-migration.md - Spring Boot 4.0变更
Quick Decision Tree
快速决策树
Testing a controller endpoint?
Yes → @WebMvcTest with MockMvcTester
Testing repository queries?
Yes → @DataJpaTest with Testcontainers (real DB)
Testing business logic in service?
Yes → Plain JUnit + Mockito (no Spring context)
Testing external API client?
Yes → @RestClientTest with MockRestServiceServer
Testing JSON mapping?
Yes → @JsonTest
Need full integration test?
Yes → @SpringBootTest with minimal context configTesting a controller endpoint?
Yes → @WebMvcTest with MockMvcTester
Testing repository queries?
Yes → @DataJpaTest with Testcontainers (real DB)
Testing business logic in service?
Yes → Plain JUnit + Mockito (no Spring context)
Testing external API client?
Yes → @RestClientTest with MockRestServiceServer
Testing JSON mapping?
Yes → @JsonTest
Need full integration test?
Yes → @SpringBootTest with minimal context configSpring Boot 4 Highlights
Spring Boot 4 亮点
- RestTestClient: Modern alternative to TestRestTemplate
- @MockitoBean: Replaces @MockBean (deprecated)
- MockMvcTester: AssertJ-style assertions for web tests
- Modular starters: Technology-specific test starters
- Context pausing: Automatic pausing of cached contexts (Spring Framework 7)
- RestTestClient: TestRestTemplate的现代替代方案
- @MockitoBean: 替代已弃用的@MockBean
- MockMvcTester: 用于Web测试的AssertJ风格断言
- 模块化启动器: 特定技术的测试启动器
- 上下文暂停: 缓存上下文自动暂停(Spring Framework 7)
Testing Best Practices
测试最佳实践
Code Complexity Assessment
代码复杂度评估
When a method or class is too complex to test effectively:
- Analyze complexity - If you need more than 5-7 test cases to cover a single method, it's likely too complex
- Recommend refactoring - Suggest breaking the code into smaller, focused functions
- User decision - If the user agrees to refactor, help identify extraction points
- Proceed if needed - If the user decides to continue with the complex code, implement tests despite the difficulty
Example of refactoring recommendation:
java
// Before: Complex method hard to test
public Order processOrder(OrderRequest request) {
// Validation, discount calculation, payment, inventory, notification...
// 50+ lines of mixed concerns
}
// After: Refactored into testable units
public Order processOrder(OrderRequest request) {
validateOrder(request);
var order = createOrder(request);
applyDiscount(order);
processPayment(order);
updateInventory(order);
sendNotification(order);
return order;
}当方法或类过于复杂而难以有效测试时:
- 分析复杂度 - 如果需要5-7个以上的测试用例才能覆盖单个方法,它可能过于复杂
- 建议重构 - 建议将代码拆分为更小、聚焦的函数
- 用户决策 - 如果用户同意重构,帮助识别提取点
- 必要时继续 - 如果用户决定保留复杂代码,仍需实现测试,尽管难度较大
重构建议示例:
java
// Before: Complex method hard to test
public Order processOrder(OrderRequest request) {
// Validation, discount calculation, payment, inventory, notification...
// 50+ lines of mixed concerns
}
// After: Refactored into testable units
public Order processOrder(OrderRequest request) {
validateOrder(request);
var order = createOrder(request);
applyDiscount(order);
processPayment(order);
updateInventory(order);
sendNotification(order);
return order;
}Avoid Code Redundancy
避免代码冗余
Create helper methods for commonly used objects and mock setup to enhance readability and maintainability.
创建常用对象和模拟设置的辅助方法,以提升可读性和可维护性。
Test Organization with @DisplayName
使用@DisplayName组织测试
Use descriptive display names to clarify test intent:
java
@Test
@DisplayName("Should calculate discount for VIP customer")
void shouldCalculateDiscountForVip() { }
@Test
@DisplayName("Should reject order when customer has insufficient credit")
void shouldRejectOrderForInsufficientCredit() { }使用描述性的显示名称明确测试意图:
java
@Test
@DisplayName("Should calculate discount for VIP customer")
void shouldCalculateDiscountForVip() { }
@Test
@DisplayName("Should reject order when customer has insufficient credit")
void shouldRejectOrderForInsufficientCredit() { }Test Coverage Order
测试覆盖顺序
Always structure tests in this order:
- Main scenario - The happy path, most common use case
- Other paths - Alternative valid scenarios, edge cases
- Exceptions/Errors - Invalid inputs, error conditions, failure modes
始终按以下顺序组织测试:
- 主场景 - 正常路径,最常见的用例
- 其他路径 - 其他有效场景、边缘情况
- 异常/错误 - 无效输入、错误条件、故障模式
Test Production Scenarios
测试生产场景
Write tests with real production scenarios in mind. This makes tests more relatable and helps understand code behavior in actual production cases.
结合真实生产场景编写测试。这会让测试更贴合实际,有助于理解代码在真实生产环境中的行为。
Test Coverage Goals
测试覆盖率目标
Aim for 80% code coverage as a practical balance between quality and effort. Higher coverage is beneficial but not the only goal.
Use Jacoco maven plugin for coverage reporting and tracking.
Coverage Rules:
- 80+% coverage minimum
- Focus on meaningful assertions, not just execution
What to Prioritize:
- Business-critical paths (payment processing, order validation)
- Complex algorithms (pricing, discount calculations)
- Error handling (exceptions, edge cases)
- Integration points (external APIs, databases)
将80%的代码覆盖率作为质量与投入之间的实际平衡点。更高的覆盖率有益,但并非唯一目标。
使用Jacoco Maven插件进行覆盖率报告和跟踪。
覆盖率规则:
- 最低80%+覆盖率
- 聚焦有意义的断言,而非仅执行代码
优先覆盖内容:
- 业务关键路径(支付处理、订单验证)
- 复杂算法(定价、折扣计算)
- 错误处理(异常、边缘情况)
- 集成点(外部API、数据库)
Dependencies (Spring Boot 4)
依赖(Spring Boot 4)
xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- For WebMvc tests -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webmvc-test</artifactId>
<scope>test</scope>
</dependency>
<!-- For Testcontainers -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-testcontainers</artifactId>
<scope>test</scope>
</dependency>xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- For WebMvc tests -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webmvc-test</artifactId>
<scope>test</scope>
</dependency>
<!-- For Testcontainers -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-testcontainers</artifactId>
<scope>test</scope>
</dependency>