题目
解释Mock与Stub的区别及使用场景
信息
- 类型:问答
- 难度:⭐
考点
Mock概念,Stub概念,测试替身区别,使用场景
快速回答
Mock和Stub都是测试替身(Test Doubles),用于隔离被测对象的外部依赖:
- Stub:提供预定义响应的简单替代品,用于控制测试输入
- Mock:验证对象间交互行为的替身,关注方法调用细节
- 关键区别:Stub关注状态(返回什么),Mock关注行为(如何调用)
1. 核心概念
Stub(桩):模拟依赖对象的简单实现,返回预设的固定响应。例如硬编码返回特定值或异常。
Mock(模拟对象):记录并验证与被测对象的交互细节(如方法调用次数、参数值)。
2. 代码示例
// Stub示例:模拟支付接口
class PaymentStub {
process(amount) {
return { success: true }; // 硬编码成功响应
}
}
// Mock示例:使用Jest验证调用
test('should send email once', () => {
const emailServiceMock = {
send: jest.fn() // 创建Mock函数
};
userService.notifyUser(emailServiceMock);
expect(emailServiceMock.send).toHaveBeenCalledTimes(1); // 验证调用次数
});3. 使用场景对比
| 场景 | Stub适用 | Mock适用 |
|---|---|---|
| 需要固定返回值 | ✅(如模拟数据库返回测试数据) | ❌ |
| 验证对象交互行为 | ❌ | ✅(如检查邮件是否发送) |
| 触发异常路径 | ✅(如模拟网络错误) | ❌ |
4. 最佳实践
- 优先使用Stub:当仅需控制依赖输出时(更简单稳定)
- 谨慎使用Mock:过度验证会导致测试脆弱(如验证具体参数而非结果)
- 遵循"Stub Queries, Mock Actions"原则:查询操作用Stub,命令操作用Mock
5. 常见错误
- 混淆概念:在不需要验证行为时使用Mock增加复杂度
- 过度指定:用Mock验证非核心交互(如内部私有方法调用)
- 忽略清理:未重置全局Mock状态影响其他测试
6. 扩展知识
- 其他测试替身:Dummy(空对象)、Fake(简易实现如内存数据库)、Spy(记录调用的Stub)
- 工具推荐:Jest(JavaScript)、Mockito(Java)、unittest.mock(Python)
- 设计影响:过度依赖Mock可能表明代码耦合度高,需考虑重构