Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Xcode Async Unit Tests waiting on Main Thread

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.

like image 335
Darnell Campbell Avatar asked Aug 21 '17 06:08

Darnell Campbell


People also ask

Should you unit test async code?

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.

How do I test an async/await function in Swift?

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.

Which unit test frameworks support async and await tests?

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.

How to run asynchronous tests in setup?

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:


2 Answers

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

like image 87
BetterLateThanNever Avatar answered Oct 01 '22 02:10

BetterLateThanNever


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)
}
like image 45
Chen OT Avatar answered Oct 01 '22 02:10

Chen OT