Skip to content

单元测试 ​

单元测试是保证代码质量的基础。

📋 JUnit 测试框架 ​

单元测试示例:

java
@SpringBootTest
class UserServiceTest {
    @Autowired
    private UserService userService;
    
    @MockBean
    private UserRepository userRepository;
    
    @Test
    void testGetUserById() {
        // 准备测试数据
        User user = new User();
        user.setId(1L);
        user.setName("John");
        
        // Mock行为
        when(userRepository.findById(1L)).thenReturn(Optional.of(user));
        
        // 执行测试
        User result = userService.getUserById(1L);
        
        // 验证结果
        assertNotNull(result);
        assertEquals("John", result.getName());
    }
}

🎯 Mock 测试 ​

Mock测试用于模拟外部依赖,隔离测试单元。

1. Mockito 使用示例 ​

Mockito 基础用法:

java
@ExtendWith(MockitoExtension.class)
class UserServiceTest {
    @Mock
    private UserRepository userRepository;
    
    @InjectMocks
    private UserService userService;
    
    @Test
    void testGetUserById() {
        // 准备测试数据
        User user = new User();
        user.setId(1L);
        user.setName("John");
        user.setEmail("john@example.com");
        
        // Mock行为
        when(userRepository.findById(1L))
            .thenReturn(Optional.of(user));
        
        // 执行测试
        User result = userService.getUserById(1L);
        
        // 验证结果
        assertNotNull(result);
        assertEquals("John", result.getName());
        assertEquals("john@example.com", result.getEmail());
        
        // 验证方法调用
        verify(userRepository, times(1)).findById(1L);
    }
    
    @Test
    void testGetUserByIdNotFound() {
        // Mock返回空
        when(userRepository.findById(999L))
            .thenReturn(Optional.empty());
        
        // 验证抛出异常
        assertThrows(UserNotFoundException.class, () -> {
            userService.getUserById(999L);
        });
    }
}

2. 测试覆盖率 ​

代码覆盖率指标:

  • 行覆盖率(Line Coverage):执行的代码行数比例
  • 分支覆盖率(Branch Coverage):执行的分支路径比例
  • 方法覆盖率(Method Coverage):执行的方法比例
  • 类覆盖率(Class Coverage):执行的类比例

覆盖率目标:

覆盖率类型目标说明
行覆盖率> 80%核心业务逻辑应该达到更高
分支覆盖率> 70%确保所有分支路径都被测试
方法覆盖率> 90%所有公共方法都应该有测试

3. 测试最佳实践 ​

测试原则:

  • FIRST原则:Fast(快速)、Independent(独立)、Repeatable(可重复)、Self-Validating(自验证)、Timely(及时)
  • AAA模式:Arrange(准备)、Act(执行)、Assert(断言)
  • 测试隔离:每个测试应该独立,不依赖其他测试

测试示例:

java
@Test
void testCreateUser() {
    // Arrange(准备)
    CreateUserRequest request = new CreateUserRequest();
    request.setName("John");
    request.setEmail("john@example.com");
    
    User savedUser = new User();
    savedUser.setId(1L);
    savedUser.setName("John");
    savedUser.setEmail("john@example.com");
    
    when(userRepository.save(any(User.class)))
        .thenReturn(savedUser);
    
    // Act(执行)
    User result = userService.createUser(request);
    
    // Assert(断言)
    assertNotNull(result);
    assertEquals(1L, result.getId());
    assertEquals("John", result.getName());
    verify(userRepository, times(1)).save(any(User.class));
}

📋 测试框架对比 ​

框架特点适用场景
JUnit标准Java测试框架Java项目
TestNG功能更强大复杂测试场景
MockitoMock框架依赖隔离
PowerMock支持静态方法Mock遗留代码测试
AssertJ流畅断言更易读的断言

参考资源:

📋 测试策略 ​

1. 测试金字塔 ​

2. 测试用例设计 ​

测试用例设计方法:

  • 等价类划分:将输入分为有效和无效等价类
  • 边界值分析:测试边界值和边界附近的值
  • 错误推测:根据经验推测可能的错误场景

3. 测试数据管理 ​

测试数据策略:

  • 测试夹具(Fixture):准备标准化的测试数据
  • 数据生成:使用工具生成测试数据
  • 数据隔离:每个测试使用独立的数据,避免相互影响

📖 学习资源 ​

视频教程 ​

书籍推荐 ​

  • 《JUnit实战》 - Petar Tahchiev
  • 《单元测试的艺术》 - Roy Osherove
  • 《测试驱动开发:实战与模式解析》 - 肯特·贝克
  • 《有效单元测试》 - Lasse Koskela

网站资源 ​

工具推荐 ​

  • 测试框架:JUnit、TestNG、pytest
  • Mock框架:Mockito、PowerMock、EasyMock
  • 覆盖率工具:JaCoCo、Cobertura、Clover
  • 测试报告:Allure、Surefire、Gradle Test Report

✅ 单元测试检查清单 ​

  • [ ] 单元测试覆盖率达标(>80%)
  • [ ] 核心业务逻辑有完整测试
  • [ ] 边界条件和异常场景有测试
  • [ ] 使用了Mock隔离外部依赖
  • [ ] 测试用例遵循FIRST原则
  • [ ] 测试数据管理规范
  • [ ] 测试执行快速可靠

上一章节:测试能力概览
下一章节:接口测试
返回目录:工程架构能力