rooscous
rooscous

Reputation: 511

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

From the documentation:

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.

Also:

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".

If a spy is just an interface layer between a real object and the caller, why not just use the real object? What does using a spy offer that using the real object or a Mock do not?

It seems to be in this void between a Mock and a real object to me.

Upvotes: 2

Views: 1230

Answers (3)

Leonard Brünings
Leonard Brünings

Reputation: 13242

Spies can be used in different scenarios. However, it is good if you can implement your tests without resorting to spies.

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

  1. They can be used to verify that a method was called without mocking the method itself
  2. You can stub out calls that you don't want to happen
  3. You can use partial mocks to test the object itself

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

Example and quote are from the docs @ http://spockframework.org/spock/docs/1.1/all_in_one.html#Spies

Upvotes: 3

Dmytro Maslenko
Dmytro Maslenko

Reputation: 2297

In my practice I prefer to use a real objects as much as possible. In case when only one method is to be mocked I still use a real object but with overridden needed method:

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

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

Note, this way works only of overridden method is not final. Otherwise Spy will help to define a behavior of this method.

Upvotes: 1

mszalbach
mszalbach

Reputation: 11470

A spy offers the possibility to use the original object but also mock out one method. For example you have a class where you want to test the implementation of the toString() method. But this calls an long running method which needs some external access like a database. In this case you use a spy and let your long running method return some test string and then use the toString from the original object.

Or like the spock example the method subscriber.receive maybe needs a server which sends out asynchronous messages. To write an test for subscriber not relying on the server or to handle asynchronous complexity you let the spy return ok and can easily test your methods which will rely on a server ok.

Upvotes: 0

Related Questions