Java单元测试中使用 Spy (间谍)而不使用使用真实对象的原因
·
在单元测试中,之所以选择使用 Spy(间谍) 而不是直接使用真实对象,主要有三个核心原因:
1. 能够“监视”行为(Verify)
如果你直接使用真实对象,你只能看到结果,却无法确认内部发生了什么。
- 真实对象:你调用
list.add("Hello"),它只会告诉你是成功了,但它不会记录你是否真的调用了这个方法。 - Spy:它像一个“监控摄像头”。除了执行正常逻辑外,它还记录了:
- 这个方法被调用了几次?
- 传入的参数是什么?
- 调用顺序是否正确?
例子: 如果你在写一个账户转账系统,使用真实对象你只能查到余额变了。但使用 Spy,你可以验证代码内部确实调用了“记录日志”这个方法,而不仅仅是修改了余额。
2. 能够“劫持”关键逻辑(Stubbing)
有时候,一个真实对象太“笨重”了,或者包含了我们不想触发的逻辑。
- 真实对象的问题:如果这个对象内部包含了一些“危险”行为,比如:连接真实的数据库、发送真实的邮件请求、调用收费的第三方 API。你在运行单元测试时,如果直接用它,测试环境会变得不可控,甚至产生费用或脏数据。
- Spy 的优势:你可以只对它其中的某一个方法进行“劫持”(Stubbing),让它返回你指定的值,而让其余的方法保持真实的行为。
你可以理解为: 它是“真实对象”的改良版。你保留了它 90% 的真实逻辑,但通过 Spy 屏蔽了那 10% 会导致测试失败或不稳定的危险逻辑。
3. 可控性与隔离性
单元测试的核心是“隔离”。我们希望测试的是“当前的逻辑”,而不是整个系统的运行情况。
- 如果我们直接使用真实对象(比如真实连接了数据库),一旦数据库挂了,你的测试就会失败,但这并不代表你的代码写错了。这种测试叫“集成测试”,耗时且不稳定。
- 使用 Spy,你可以把复杂的外部依赖转化为可控的操作,确保你的测试只针对你的代码逻辑,无论外部环境如何,测试结果永远是确定且快速的。
总结对比表
| 特性 | 直接使用真实对象 | 使用 Spy (间谍) |
|---|---|---|
| 功能执行 | 运行真实逻辑 | 运行真实逻辑 |
| 可否调用验证 (Verify) | 不能 | 能 |
| 可否部分修改行为 (Stub) | 不能 | 能 |
| 是否依赖外部环境 | 高(容易报错) | 低(更加稳定) |
更多推荐


所有评论(0)