Izbassar Tolegen
Izbassar Tolegen

Reputation: 2152

How to write parametrized tests with groovy-spock using mocks

I want to test this class using groovy with spock:

class TaskRunner {
    private int threads
    private ExecutorService executorService
    private TaskFactory taskFactory

    // relevant constructor

    void update(Iterable<SomeData> dataToUpdate) {
        Iterable<List<SomeData>> partitions = partition(dataToUpdate, THREADS)
        partitions.each {
            executorService.execute(taskFactory.createTask(it))
        }
    }
}

I want to write test looking like this one:

class TaskRunnerSpec extends specification {
    ExecutorService executorService = Mock(ExecutorService)
    TaskFactory taskFactory = Mock(TaskFactory)
    @Subject TaskRunner taskRunner = new TaskRunner(taskFactory, executorService)

    def "should run tasks partitioned by ${threads} value"(int threads) {
        given:
        taskRunner.threads = threads

        where:
        threads | _
              1 | _
              3 | _
              5 | _

        when:
        tasksRunner.update(someDataToUpdate())

        then:
        // how to test number of invocations on mocks?
    }
}

I see examples from documentation with only interacting testing with sections given, when, then and examples with data-driven tests, which have only two sections: expect and where.

May I combine that two? Or how to achieve the same functionality?

Upvotes: 1

Views: 490

Answers (2)

Dmytro Maslenko
Dmytro Maslenko

Reputation: 2297

BTW, the where block can be simplified to one line:

where:
threads << [1, 3, 5]

Upvotes: 0

Leonard Br&#252;nings
Leonard Br&#252;nings

Reputation: 13222

Short answer yes they can be combined, but not in that order see the docs where must be the last block. So given-when-then-where is perfectly fine. Correctly testing multi-threaded code is a lot harder, but since you mock the ExecutorService you don't have to worry about it.

Don't forget @Unroll and note that the templating is not using GString syntax.

class TaskRunnerSpec extends specification {
    ExecutorService executorService = Mock(ExecutorService)
    TaskFactory taskFactory = Mock(TaskFactory)
    @Subject TaskRunner taskRunner = new TaskRunner(taskFactory, executorService)

    @Unroll
    def "should run tasks partitioned by #threads value"(int threads) {
        given:
        taskRunner.threads = threads

        when:
        tasksRunner.update(someDataToUpdate())

        then:
        threads * taskFactory.createTask(_) >> new Task() // or whatever it creates
        threads * executorService.execute(_)

        where:
        threads | _
              1 | _
              3 | _
              5 | _

    }
}

Upvotes: 1

Related Questions