一、分层测试体系与工具选型
1.1 测试金字塔原则
- 单元测试(70%):聚焦最小可测试单元,验证方法逻辑正确性
- 集成测试(20%):验证模块间交互及外部依赖集成
- 端到端测试(10%):模拟用户场景验证系统整体行为
1.2 工具链整合
xml
|
<!-- Maven依赖配置示例 --> |
|
<dependencies> |
|
<!-- JUnit 5核心 --> |
|
<dependency> |
|
<groupId>org.junit.jupiter</groupId> |
|
<artifactId>junit-jupiter</artifactId> |
|
<version>5.9.0</version> |
|
<scope>test</scope> |
|
</dependency> |
|
<!-- Mockito核心 --> |
|
<dependency> |
|
<groupId>org.mockito</groupId> |
|
<artifactId>mockito-core</artifactId> |
|
<version>4.11.0</version> |
|
<scope>test</scope> |
|
</dependency> |
|
<!-- Spring Boot测试集成 --> |
|
<dependency> |
|
<groupId>org.springframework.boot</groupId> |
|
<artifactId>spring-boot-starter-test</artifactId> |
|
<scope>test</scope> |
|
</dependency> |
|
</dependencies> |
二、单元测试层实践
2.1 基础Mock对象创建
java
|
// 使用@Mock注解创建模拟对象 |
|
@ExtendWith(MockitoExtension.class) |
|
class UserServiceTest { |
|
@Mock |
|
private UserRepository userRepository; |
|
|
|
@InjectMocks |
|
private UserService userService; |
|
} |
2.2 行为验证与Stubbing
java
|
@Test |
|
void shouldSaveUserSuccessfully() { |
|
// 模拟依赖行为 |
|
User mockUser = new User("test", "test@example.com"); |
|
when(userRepository.save(any(User.class))).thenReturn(mockUser); |
|
|
|
// 执行测试逻辑 |
|
User result = userService.registerUser("test", "test@example.com"); |
|
|
|
// 验证结果与交互 |
|
assertEquals("test", result.getUsername()); |
|
verify(userRepository, times(1)).save(any()); |
|
} |
2.3 异常场景测试
java
|
@Test |
|
void shouldThrowExceptionWhenUserNotFound() { |
|
when(userRepository.findById(anyLong())).thenReturn(Optional.empty()); |
|
|
|
assertThrows(UserNotFoundException.class, () -> { |
|
userService.activateUser(999L); |
|
}); |
|
|
|
verify(userRepository, never()).save(any()); |
|
} |
三、集成测试层实践
3.1 Spring上下文集成
java
|
@SpringBootTest |
|
class OrderServiceIntegrationTest { |
|
@Autowired |
|
private OrderService orderService; |
|
|
|
@MockBean |
|
private PaymentGateway paymentGateway; |
|
|
|
@Test |
|
void shouldProcessOrderWithPayment() { |
|
when(paymentGateway.charge(anyDouble())).thenReturn(true); |
|
|
|
Order order = orderService.createOrder(100.0); |
|
|
|
assertTrue(order.isPaid()); |
|
} |
|
} |
3.2 数据库交互测试
java
|
@DataJpaTest |
|
@Transactional |
|
class ProductRepositoryTest { |
|
@Autowired |
|
private ProductRepository productRepository; |
|
|
|
@Test |
|
void shouldFindProductsByCategory() { |
|
List<Product> result = productRepository.findByCategory("Electronics"); |
|
|
|
assertEquals(3, result.size()); |
|
} |
|
} |
四、端到端测试层实践
4.1 REST API测试
java
|
@WebMvcTest(UserController.class) |
|
class UserControllerE2ETest { |
|
@Autowired |
|
private MockMvc mockMvc; |
|
|
|
@MockBean |
|
private UserService userService; |
|
|
|
@Test |
|
void shouldReturnUserList() throws Exception { |
|
List<User> mockUsers = Arrays.asList(new User(), new User()); |
|
when(userService.getAllUsers()).thenReturn(mockUsers); |
|
|
|
mockMvc.perform(get("/api/users")) |
|
.andExpect(status().isOk()) |
|
.andExpect(jsonPath("$.length()").value(2)); |
|
} |
|
} |
4.2 界面交互测试(示例)
java
|
// 使用Selenium的伪代码示例 |
|
@Test |
|
void shouldSubmitLoginFormSuccessfully() { |
|
driver.get("/login"); |
|
driver.findElement(By.id("username")).sendKeys("admin"); |
|
driver.findElement(By.id("password")).sendKeys("password"); |
|
driver.findElement(By.id("submit")).click(); |
|
|
|
assertEquals("Dashboard", driver.getTitle()); |
|
} |
五、高级实践与优化策略
5.1 参数化测试
java
|
@ParameterizedTest |
|
@ValueSource(strings = {"active", "inactive", "pending"}) |
|
void shouldFilterUsersByStatus(String status) { |
|
List<User> result = userService.filterByStatus(status); |
|
|
|
assertTrue(result.stream().allMatch(u -> u.getStatus().equals(status))); |
|
} |
5.2 测试覆盖率优化
- 使用Jacoco生成覆盖率报告
- 目标:行覆盖率>85%,分支覆盖率>75%
5.3 并行测试执行
properties
|
# Maven Surefire配置 |
|
<configuration> |
|
<parallel>methods</parallel> |
|
<threadCount>4</threadCount> |
|
</configuration> |
六、常见问题与解决方案
6.1 Mock对象未初始化问题
java
|
// 正确初始化方式 |
|
@ExtendWith(MockitoExtension.class) |
|
public class ServiceTest { |
|
@Mock |
|
private Dependency dependency; |
|
} |
6.2 测试方法间状态污染
java
|
// 使用@BeforeEach重置状态 |
|
@BeforeEach |
|
void setUp() { |
|
Mockito.reset(mockObject); |
|
} |
6.3 验证方法调用顺序
java
|
InOrder inOrder = inOrder(firstMock, secondMock); |
|
inOrder.verify(firstMock).doSomething(); |
|
inOrder.verify(secondMock).doSomethingElse(); |
七、总结与展望
通过JUnit 5与Mockito的深度整合,结合分层测试策略,能够构建出高效、可维护的测试体系。未来可探索:
- AI驱动的测试用例生成
- 基于流量的自动化测试
- 跨语言测试框架整合
本文所述实践已在多个企业级项目中验证,能够有效提升测试效率与代码质量。开发团队应根据具体业务场景调整测试策略,持续优化测试覆盖率与执行效率。