Spock框架:间谍与使用真实对象或模拟的目的是什么?

时间:2017-07-24 13:42:35

标签: groovy spock

来自文档:

  

间谍总是基于真实物体。因此,您必须提供类类型而不是接口类型,以及该类型的任何构造函数参数。如果没有提供构造函数参数,则将使用类型的默认构造函数。

     

对间谍的方法调用会自动委托给真实对象。同样,从真实对象的方法返回的值将通过间谍传递回调用者。

此外:

  

在间谍上存根方法时,不再调用真正的方法:

subscriber.receive(_) >> "ok"

  

接收方法现在只返回“ok”而不是调用SubscriberImpl.receive。

如果间谍只是真实对象和调用者之间的接口层,为什么不只使用真实对象?使用真实对象或模拟的间谍提议有什么用呢?

似乎是在模拟和真实物体之间的这个空隙中。

3 个答案:

答案 0 :(得分:1)

在我的练习中,我更喜欢尽可能多地使用真实物体。如果只有一个方法被模拟,我仍然使用一个真实的对象,但需要重写所需的方法:

MyDomainClass myRealObjectWithMockedMethod = new MyDomainClass() {
    @Override
    Object doSomething() {
        return "hard coded or mocked result";
    }
}

// test what you need
myRealObjectWithMockedMethod.action();
注意,这种方式只适用于重写方法不是最终的。否则Spy将帮助定义此方法的行为。

答案 1 :(得分:1)

间谍可以在不同的场景中使用。但是,如果您可以在不诉诸间谍的情况下实施测试,那就太好了。

  

(在使用此功能之前请三思。更改规范下的代码设计可能会更好。)

  1. 它们可用于验证方法是否被调用而不模拟方法本身
  2. 你可以找出你不想发生的电话
  3. 您可以使用部分模拟测试对象本身
  4. 
        // 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的方法。