Search code examples
unit-testinggroovymockingspock

Spock: mock a method with varargs


This question is an offshoot of this Q&A: Test Groovy class that uses System.console()

The problem:

Spock framework incorrectly checks arguments of the mocked method with varargs.

Steps to reproduce:

1) Create groovy project

2) Create an interface:

interface IConsole {
  String readLine(String fmt, Object ... args)
}

3) Create spock test:

class TestInputMethods extends Specification {

  def 'test console input'() {
    setup:
    def consoleMock = GroovyMock(IConsole)
    1 * consoleMock.readLine(_) >> 'validResponse'

    when:
    // here we get exception "wrong number of arguments":
    def testResult = consoleMock.readLine('testPrompt')

    then:
    testResult == 'validResponse'
  }
}

4) try running the test

Effect: test fails with exception "wrong number of arguments".

Workaround:

call to readLine is replaced with:

def testResult = consoleMock.readLine('testPrompt', [] as Object[])

then test completes successfully.

Question:

is there a better way to "explain" spock that the last argument of the mocked function is vararg and, as such, it could be omitted?


Solution

  • You can avoid having to explain the varargs by using Mock() instead of GroovyMock().

    In general, when writing Spock specifications you should prefer Spock's Mock object over Groovy's GroovyMock unless you intend to use some of the unique functionality from GroovyMock. Reference

    Swapping out Mock for GroovyMock allows you to avoid the verbose Object params:

            setup:
                def consoleM = Mock(IConsole)
                1 * consoleM.readline(_) >> "hey"
    
            when:
                def result = consoleM.readline("prompt")
    
            then:
                result == "hey"