Mock only some methods with Spock

This article is the 25th day of G * Advent Calendar Advent Calendar 2016. The day before was @ hikariru's Using HTTP client with Grails (of course I also write a test).

G * only started touching Spock about half a year ago, but since the last day was free, I will take the plunge and post it. Although I have a short history, I have realized that the flexibility of Groovy / Spock is effective in testing.

Overview

I will write about how to Mock only some methods with Spock.

It is assumed that you want to Mock only the non-target method when the test target method calls another method of the same object.

The test target class is written in Java.

Tested class

public class Name {

  private String firstName;
  private String lastName;

  public Name(String firstName, String lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
  }

  public String getFullName() {
    return getFirstName() + " " + getLastName();
  }

  public String getFirstName() {
    return firstName;
  }

  public String getLastName() {
    return lastName;
  }
}

Use Spy for Mock some methods

By using Spy, only some methods can be replaced.

class NameSpec extends Specification {
    def "Try Spy"() {
        setup:
        //Spy by passing constructor arguments
        def spiedName = Spy(Name, constructorArgs: ['Taro', 'Yamada'])
        //Rewrite only some methods
        spiedName.getFirstName() >> 'Hanako'

        expect:
        //Rewritten method
        spiedName.getFirstName() == 'Hanako'
        //The method that has not been rewritten works as it is
        spiedName.getLastName() == 'Yamada'
        //Internally called methods work equally well
        spiedName.getFullName() == 'Hanako Yamada'
    }
}

Proper use with Mock and Stub

For reference, check the case of Mock and Stub as well.

For Mock

Mock will mock the entire object. All Mock behavior should be explicit (if necessary).

def "Try Mock" () {
    setup:
    def mockedName = Mock(Name)
    //Rewrite only some methods
    mockedName.getFirstName() >> 'Taro'

    expect:
    //Rewritten method
    mockedName.getFirstName() == 'Taro'
    //Unrewritten methods do nothing
    mockedName.getLastName() == null
    //Do nothing even with internally called methods
    mockedName.getFullName() == null
}

For Stub

The entire object of a Stub becomes a Stub. You can rewrite the Stub value (return value). The unrewritten method returns an appropriate value such as an empty string or dummy object.

def "Try Stub"() {
    setup:
    def stubbedName = Stub(Name)
    //Rewrite only some methods
    stubbedName.getFirstName() >> 'Taro'

    expect:
    //Rewritten method
    stubbedName.getFirstName() == 'Taro'
    //Unrewritten method returns an appropriate value
    stubbedName.getLastName() == ''
    //Ignore internally called methods and return the appropriate value
    stubbedName.getFullName() == ''
}

Please note that in the case of Stub, an exception will occur if you execute the test of the number of calls possible with Mock or Spy.

//InvalidSpecException thrown
1 * stubbedName.getFirstName()

Summary

--Use Spy to rewrite some methods --Use properly with Mock and Stub --Spock is fun

reference

Recommended Posts

Mock only some methods with Spock
Mock static methods with PowerMock
Make System.out a Mock with Spock Test Framework
[Note] Methods ending with?
Mock Enums with PowerMock
How to mock some methods of the class under test
Mock the constructor with PowerMock
Streamline Java testing with Spock
Mock static methods in Mockito 3.4