来自文档:
间谍总是基于真实物体。因此,您必须提供类类型而不是接口类型,以及该类型的任何构造函数参数。如果没有提供构造函数参数,则将使用类型的默认构造函数。
对间谍的方法调用会自动委托给真实对象。同样,从真实对象的方法返回的值将通过间谍传递回调用者。
此外:
在间谍上存根方法时,不再调用真正的方法:
subscriber.receive(_) >> "ok"
接收方法现在只返回“ok”而不是调用SubscriberImpl.receive。
如果间谍只是真实对象和调用者之间的接口层,为什么不只使用真实对象?使用真实对象或模拟的间谍提议有什么用呢?
似乎是在模拟和真实物体之间的这个空隙中。
答案 0 :(得分:1)
在我的练习中,我更喜欢尽可能多地使用真实物体。如果只有一个方法被模拟,我仍然使用一个真实的对象,但需要重写所需的方法:
MyDomainClass myRealObjectWithMockedMethod = new MyDomainClass() {
@Override
Object doSomething() {
return "hard coded or mocked result";
}
}
// test what you need
myRealObjectWithMockedMethod.action();
注意,这种方式只适用于重写方法不是最终的。否则Spy将帮助定义此方法的行为。
答案 1 :(得分:1)
间谍可以在不同的场景中使用。但是,如果您可以在不诉诸间谍的情况下实施测试,那就太好了。
(在使用此功能之前请三思。更改规范下的代码设计可能会更好。)
// this is now the object under specification, not a collaborator
def persister = Spy(MessagePersister) {
// stub a call on the same object
isPersistable(_) >> true
}
when:
persister.receive("msg")
then:
// demand a call on the same object
1 * persister.persist("msg")
示例和引用来自文档@ http://spockframework.org/spock/docs/1.1/all_in_one.html#Spies
答案 2 :(得分:0)
间谍提供了使用原始对象的可能性,但也模拟了一种方法。例如,您有一个要测试toString()
方法实现的类。但这会调用一个长时间运行的方法,需要像数据库一样进行外部访问。在这种情况下,您使用间谍并让您的长时间运行方法返回一些测试字符串,然后使用原始对象中的toString
。
或者像spock示例一样,方法subscriber.receive
可能需要一个发送异步消息的服务器。要编写subscriber
不依赖于服务器或处理异步复杂性的测试,您可以让间谍返回ok
并轻松测试依赖于服务器ok
的方法。