Spock 框架:Spies 与使用真实对象或 Mock 的目的是什么?

Spock framework: what is the purpose of Spies vs. a using real object or Mock?

来自文档:

A spy is always based on a real object. Hence you must provide a class type rather than an interface type, along with any constructor arguments for the type. If no constructor arguments are provided, the type’s default constructor will be used.

Method calls on a spy are automatically delegated to the real object. Likewise, values returned from the real object’s methods are passed back to the caller via the spy.

另外:

When stubbing a method on a spy, the real method no longer gets called:

subscriber.receive(_) >> "ok"

Instead of calling SubscriberImpl.receive, the receive method will now simply return "ok".

如果间谍只是真实对象和调用者之间的接口层,为什么不直接使用真实对象呢?使用间谍可以提供哪些使用真实对象或 Mock 不能提供的功能?

对我来说,它似乎介于模拟对象和真实对象之间。

间谍提供了使用原始对象的可能性,但也模拟了一种方法。例如,您有一个 class,您希望在其中测试 toString() 方法的实现。但这调用了一个 long 运行 方法,它需要一些外部访问,比如数据库。在这种情况下,您使用间谍并让您的长 运行 方法 return 一些测试字符串,然后使用原始对象中的 toString

或者像 spock 示例一样,方法 subscriber.receive 可能需要一个发送异步消息的服务器。要为 subscriber 编写不依赖服务器的测试或处理异步复杂性,您可以让间谍 return ok 并且可以轻松地测试您将依赖服务器的方法 ok.

在我的实践中,我更喜欢尽可能使用真实的对象。如果只有一种方法被模拟,我仍然使用一个真实的对象,但需要覆盖的方法:

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

// test what you need
myRealObjectWithMockedMethod.action();

请注意,此方法仅适用于重写方法,并非最终方法。否则 Spy 将帮助定义此方法的行为。

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

(Think twice before using this feature. It might be better to change the design of the code under specification.)

  1. 它们可用于验证方法是否被调用而无需模拟方法本身
  2. 您可以停止不想发生的来电
  3. 您可以使用部分模拟来测试对象本身

    // 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