如何使用 groovy-spock 使用模拟编写参数化测试

How to write parametrized tests with groovy-spock using mocks

我想使用 groovy 和 spock 来测试这个 class:

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))
        }
    }
}

我想写这样的测试:

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?
    }
}

我看到文档中的示例仅包含 givenwhenthen 部分的交互测试以及数据驱动测试的示例,它们只有两个部分:expectwhere.

我可以把这两个结合起来吗?或者如何实现相同的功能?

简短回答是的,它们可以组合,但不能按此顺序查看 docs where 必须是最后一个块。所以 given-when-then-where 完全没问题。正确测试多线程代码要困难得多,但由于你模拟了 ExecutorService 你不必担心它。

不要忘记 @Unroll 并注意模板未使用 GString 语法。

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

    }
}

顺便说一句,where 块可以简化为一行:

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