I'm trying to test some asynchronous code using Unit Tests in Xcode, but I'm getting a blocked main thread.
The problem is that some of the code being tested expects to receive a callback from an iOS class (AVFoundation). However, it seems the AVFoundation class will only callback on the Main thread.
The problem is that if I'm doing an async unit test, then the test actually blocks the main thread while it's waiting, so the callback can never be sent.
I'm pretty sure this is the problem. Is there any way to run the tests from another thread or have an XCTWaiter
that doesn't block the main thread?
Edit: After looking a bit at the docs, it seems like the best way to do this would be to run the entire test case on a background thread. However, in my current project the testing is all set up automatically. I wonder if anyone knows how to setup a test case / run manually. That way I could run it on another thread.
It’s easier to add features or fix bugs in tested code, because the unit tests act as a safety net while the code is changing. Writing unit tests for asynchronous code brings a few unique challenges. Furthermore, the current state of async support in unit test and mocking frameworks varies and is still evolving.
Because async/await is a feature at the Swift language level, to test an async function we can use the same approach we'd use to consume that code in production: call it with await. That's it.
Luckily, the latest versions of the major unit test frameworks—MSTest, xUnit.net and NUnit—support the async and await tests (see Stephen Cleary’s blog at bit.ly/1x18mta). Their test runners can cope with async Task tests and await the completion of the thread before they start to evaluate the assert statements.
There are two techniques for running asynchronous tests. XCTestExpectation and semaphores. In the case of doing something asynchronous in setUp, you should use the semaphore technique:
This is more than a year late so probably not relevant anymore, but I encountered this as realized that XCTestExpectation fixes the issue (not sure if that was available when you posted the question).
Waiting for expectations does not block the main thread and allows other work dispatched to the main thread asynchronously to proceed as expected. Hope this helps
Considering @BetterLateThanNever's answer. Here is the code snippet how I test my code using callback in main-thread.
func test() {
let expectation = XCTestExpectation(description: "Test")
DispatchQueue.global(qos: .default).async {
...
...
let myObj = MyObj()
myObj.runSomethingMayWaitForMainThread()
...
...
XCTAssert(myObj.result)
expectation.fulfill()
}
wait(for: [expectation], timeout: 50.0)
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With