Verify Spock mock with specified timeout
Asked Answered
P

4

10

In Mockito there is option to verify if mock method has been called, and specify timeout for this verification (VerificationWithTimeout), for example:

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

It there any equivalent to such functionality in Spock?

Physiography answered 10/2, 2014 at 0:0 Comment(0)
Q
12

I was trying to use PollingConditions to satisfy a similar scenario (which wasn't helpful), but instead found satisfaction in Spock's BlockingVariables. To verify that SomeService.method() is invoked at least once in function ClassBeingTested.method() within a given timeout period:

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

When the result is set, the blocking condition will be satisfied and result.get() would have to return true for the condition to pass. If it fails to be set within 200ms, the test will fail with a timeout exception.

Quinquevalent answered 9/2, 2015 at 17:20 Comment(0)
A
7

There is no equivalent in Spock. (PollingConditions can only be used for conditions, not for interactions.) The closest you can get is to add a sleep() statement in the then block:

when:
...

then:
sleep(200)
(1.._) * mock.baz()
Anchovy answered 20/2, 2014 at 17:50 Comment(8)
Peter - your solution causes that I always have to wait 200ms. In this case I prefer using Mockito because it just works :)Physiography
That's why I said "the closest you can get is ...".Anchovy
Is it something that is planned to be added into Spock?Physiography
Not currently. The feature sounds smelly to me, and I'm trying to resist to implement smelly mocking features.Anchovy
In this case I've integration test in which I send message to a queue and I've go check if it was received - I don't think it's smellyPhysiography
The smell is to use mocks for integration tests.Anchovy
I like such speculations - haven't looked at the code but already know it's wrong...Physiography
@PeterNiederwieser Unfortunately, your example is exactly what doesn't work with Spock. The sleep()must be in the when: block to work, see e.g. here: douevencode.com/articles/2017-11/spock-test-asynchronous-codeSpae
C
2

Using PollingConditions and a boolean variable, the following example evaluates a function until it satisfies an interaction.

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

}

Crusade answered 27/1, 2016 at 16:11 Comment(0)
I
-1

This doesn't do exactly what the question asked, but I found it a bit cleaner that using a variable. If you have other conditions to asynchronously test in addition to the interaction, then you can declare the interactions at mock creation time and then use PollingConditions to test the other conditions. PollingConditions will either fail the test or block until the conditions pass, so that by the time the interaction is tested, the method should have been called:

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


Intersex answered 11/11, 2019 at 23:9 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.