How I Test Functions Which Dispatch Tasks
• 1 minute read
Some functions dispatch tasks or code blocks to a different dispatch queue. I have wrapped the wait for that asynchronous code in an extension to XCTestCase.
This is a short one. I actually only want to share this little code snippet:
import XCTest
extension XCTestCase {
///
/// Dispatches the fulfillment of an `XCTestExpectation` to the main dispatch queue and waits for it.
///
/// This is supposed to be called after calling a function under test which dispatches tasks to the main dispatch queue.
/// Otherwise tests would likely fail due to race conditions.
/// Assertions would be executed and fail before the code under test has been executed.
///
func waitForTasksDispatchedToMainQueue() {
let expectation = expectation(description: "TasksDispatchedByFunctionUnderTestCompleted")
// Because this dispatch is called after the code under test, it is added to the end of the main dispatch queue.
DispatchQueue.main.async {
// When the expectation is fulfilled, it can be assumed that all tasks dispatched by the code under test have completed.
expectation.fulfill()
}
wait(for: [expectation], timeout: 1)
}
}
This function is available conveniently in every test case function of tests derived from XCTestCase. In your test case, after calling code which is asynchronous or dispatching asynchronous code, this needs to be called like this before assertions can work:
func testSomething() {
signIn() // Dispatches a Task or code block
waitForTasksDispatchedToMainQueue()
XCTAssertTrue(mockedDependency.signInCalled)
}
Note that this currently is designed for the main thread only.