Unit testing 使用指定的超时验证Spock模拟

Unit testing 使用指定的超时验证Spock模拟,unit-testing,testing,mocking,spock,Unit Testing,Testing,Mocking,Spock,在Mockito中,可以选择验证是否调用了mock方法,并为此验证指定超时(VerificationWithTimeout),例如: verify(mock, timeout(200).atLeastOnce()).baz(); Spock中是否有类似功能?Spock中没有类似功能。(PollingConditions只能用于条件,不能用于交互。)最接近的方法是在then块中添加sleep()语句: when: ... then: sleep(200) (1.._) * mock.baz()

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

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

Spock中是否有类似功能?

Spock中没有类似功能。(
PollingConditions
只能用于条件,不能用于交互。)最接近的方法是在
then
块中添加
sleep()
语句:

when:
...

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

我试图使用PollingConditions来满足类似的场景(这没有帮助),但却在斯波克的实验中找到了满足感。要验证在给定的超时时间内,函数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()
}
def“验证200毫秒内至少发生一次交互”(){
鉴于:
def结果=新阻塞变量(0.2)//200ms
SomeService someServiceMock=Mock()
someServiceMock.method()>>{
result.set(真)
}
ClassBeingTested clazz=新的ClassBeingTested(someService:someServiceMock)
什么时候:
clazz.someMethod()
然后:
result.get()
}

当设置结果时,阻塞条件将得到满足,result.get()必须返回true才能通过该条件。如果在200ms内设置失败,测试将失败并出现超时异常。

使用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 * _

}

这与问题所问的不完全一样,但我发现使用变量会更简洁一些。如果除了交互之外还有其他条件要异步测试,那么可以在模拟创建时声明交互,然后使用
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
        }
    }
}



彼得-你的解决方案导致我总是要等200毫秒。在这种情况下,我更喜欢使用Mockito,因为它只是工作:)而不是当前。这个功能听起来很臭,我正试图抵制实现臭烘烘的模拟功能。在这种情况下,我进行了集成测试,我将消息发送到队列,并检查是否收到消息-我不认为这是臭烘烘的味道是使用模拟进行集成测试。我喜欢这种猜测-没有看过代码,但已经知道它是错误的。。。