使用指定的超时验证Spock mock

时间:2014-02-10 00:00:16

标签: unit-testing testing mocking spock

在Mockito中,可以选择验证是否已调用mock方法,并为此验证指定超时(VerificationWithTimeout),例如:

verify(mock, timeout(200).atLeastOnce()).baz();

在Spock中有没有相当于这样的功能?

4 个答案:

答案 0 :(得分:7)

我试图使用PollingConditions来满足类似的场景(这并没有帮助),但却在Spock的BlockingVariables中找到了满足感。要验证在给定的超时时间内函数ClassBeingTested.method()中至少调用一次SomeService.method():

def "verify an interaction happened at least once within 200ms"(){
    given:
        def result = new BlockingVariable<Boolean>(0.2) // 200ms
        SomeService someServiceMock = Mock()
        someServiceMock.method() >> {
            result.set(true)
        }
        ClassBeingTested clazz = new ClassBeingTested(someService: someServiceMock)
    when:
        clazz.someMethod()
    then:
        result.get()
}

设置结果后,将满足阻塞条件,并且result.get()必须为要传递的条件返回true。如果未能在200ms内设置,则测试将因超时异常而失败。

答案 1 :(得分:6)

Spock没有相应的内容。 (PollingConditions只能用于条件,而不能用于互动。)您最接近的是在sleep()块中添加then语句:

when:
...

then:
sleep(200)
(1.._) * mock.baz()

答案 2 :(得分:1)

使用PollingConditions和布尔变量,以下示例评估函数,直到它满足交互。

def "test the config watcher to reload games if a new customer directory is added"() {

given:
def conditions = new PollingConditions(initialDelay: 1, timeout: 60, factor: 1.25)
def mockGameConfigLoader = Mock(GameConfigLoader)
def gameConfigWatcher= new GameConfigWatcher(mockGameConfigLoader)
boolean gamesReloaded = false

when:
conditions.eventually {
    gameConfigWatcher.listenEvents()
    assert gamesReloaded
}

then:
1 * mockGameConfigLoader.loadAllGameConfigs() >> {
    gamesReloaded = true
}
0 * _

}

答案 3 :(得分:0)

这并不能完全解决问题,但我发现使用变量更干净。如果除了交互之外还具有其他要异步测试的条件,则可以在模拟创建时声明交互,然后使用PollingConditions测试其他条件。 PollingConditions要么会失败要么无法通过测试,或者直到条件通过才阻止,因此在测试交互之前,应已调用该方法:

@MicronautTest
class KernelManagerTest extends Specification {

    @Inject
    KernelManager kernelManager

    //create conditions
    PollingConditions conditions = new PollingConditions(timeout: 10, initialDelay: 1)

    class Exits {

        static createKernel (String[] args) {
            System.exit(args[0].toInteger())
        }

    }

    def "handles a system exit from within kernel"() {
        given:
        // set custom kernel
        kernelManager.kernelClass = Exits
        // create custom logger
        kernelManager.log = Mock(Logger) {
            1 * warn("Kernel exited unexpectedly.", _ as UnexpectedExitException)
        }

        when:
        // create new kernel (exit 1)
        kernelManager.startNewKernel("1")

        then:
        conditions.eventually {
            kernelManager.kernelInstances.size() == 0
            kernelManager.kernelThreads.size() == 0
        }
    }
}