- 什么是单元测试?为何需要编写?
- 单元测试用于验证代码中最小可测试单元的正确性,通常针对具体方法进行验证。
- 核心价值:提升代码可靠性,降低缺陷率,简化后期维护。
- 常用工具:JUnit(测试框架),Mockito(模拟依赖)。
- JUnit常用注解及其功能
| 注解 |
说明 |
@测试 |
标记方法为测试用例 |
@准备 |
每个测试前执行 |
@清理 |
每个测试后执行 |
@全局准备 |
所有测试前执行(需静态方法) |
@全局清理 |
所有测试后执行(需静态方法) |
@名称("测试用例") |
定义测试名称 |
@禁用 |
跳过该测试 |
- JUnit常用断言方法
| 断言方法 |
功能 |
断言相等(预期值, 实际值) |
验证数值一致性 |
断言真(条件) |
验证条件为真 |
断言假(条件) |
验证条件为假 |
断言非空(对象) |
验证对象不为空 |
断言抛出(异常类型, () -> ...) |
验证异常触发 |
- Mockito框架的作用与优势
- Mockito是Java语言的模拟工具,通过替代依赖对象实现被测类的独立验证。
- 优势:提升测试速度,避免外部系统依赖(如数据库、接口)。
- @Mock、@注入和@部分模拟的区别
| 注解 |
功能 |
@Mock |
创建完整模拟对象 |
@注入 |
将模拟对象注入目标实例 |
@部分模拟 |
包装真实对象并选择性模拟 |
- 模拟方法返回值与异常处理
when(模拟对象.方法()).thenReturn(结果); // 定义返回值
doReturn(结果).when(部分模拟对象).方法(); // 用于部分模拟或void方法
doThrow(新异常()).when(模拟对象).方法(); // 模拟异常抛出
- 验证方法调用记录
verify(模拟对象).方法(); // 验证方法被调用
verify(模拟对象, times(2)).方法(); // 验证调用次数
verify(模拟对象, never()).方法(); // 验证未被调用
- 模拟对象与桩对象的区别
- 桩对象:仅返回预设数据;无法验证交互行为。
- 模拟对象:可定义行为并验证调用记录。
- 私有方法测试方案
- 推荐方式:通过公共方法间接测试私有逻辑。
- 不推荐:使用反射直接访问私有方法。
- 异常逻辑测试方法
使用JUnit:
断言抛出(非法参数异常.class, () -> 服务类.方法());
使用Mockito:
doThrow(新非法参数异常()).when(模拟对象).方法();
- AAA测试模式详解
| 步骤 |
含义 |
| 准备 |
初始化测试环境与模拟对象 |
| 执行 |
触发被测方法 |
| 断言 |
验证结果与预期是否一致 |
- 单元测试编写规范
- 每个测试用例聚焦单一功能
- 保持测试独立性与可重复性
- 避免真实外部依赖(使用模拟)
- 覆盖边界条件与异常场景
- 控制器类测试实践
通过MockMvc模拟HTTP请求并验证响应结果:
mockMvc.perform(请求("/api/用户/1"))
.andExpect(状态().等于200))
.andExpect(JSON路径("$.名称").等于("艾米"));
核心Mockito使用模式
@Mock // 创建模拟实例
@InjectMocks // 注入依赖到目标对象
when(...).thenReturn(...) // 定义模拟行为
verify(...) // 验证交互记录