Quick / Nimble

A Matcher Framework for Swift and Objective-C
https://quick.github.io/Nimble/documentation/nimble/
Apache License 2.0
4.81k stars 598 forks source link

async support breaks Actors with async functions #1025

Closed drekka closed 1 year ago

drekka commented 1 year ago

I have a class which I have converted to an actor that looks something like this:

enum State: String {
    case a
    case b
    case c
}

actor StateMachine {

    var state: State {...}

    func doMultithreadedAsyncThing() {
        // Does some stuff then eventually sets the state to .b
    }
}

Now because StateMachine is an actor, I have to use await state to get the state from it. Before converting to an actor I did something like this in my test:

let sm = StateMachine()
sm.doMultithreadedAsyncThing()
expect(sm.state).toEventually(equal(.b))

Now after the conversion I have to do this:

let sm = StateMachine()
await sm.doMultithreadedAsyncThing()
await expect( { await sm.state } ) == .b

However that does not work because the expect is no longer polling to wait for the state to change.

How do I get the test to wait for the state to change?

younata commented 1 year ago

Using toEventually with async expressions is not currently supported. It's on my radar, but rather low priority. Sorry.

You could kinda test this behavior by using waitUntil with a for loop that checks the state. e.g. something like:

await waitUntil { done in
    while true {
        if await sm.state == .b {
            done()
            break
        }
    }
}

But that's not a great developer experience.

drekka commented 1 year ago

I don't think that will work for my code. I was testing a situation where I was receiving a stream of state changes and wanted to wait until a specific state appeared. So either the value needs to be polled or the matcher needs to be watching a stream/publisher etc. Anyway I have some code that is working for me so no hurry on this :-)