From Apple's XCTest doc regarding setUp
and tearDown
it said to perform async code in tearDown() async throws
method.
And in my case, I create some test data in server with API call, and I'd like to clean it after the test case execution is completed. The ideal place is tearDown
from my understanding.
override func tearDown() async throws {
// This is the tearDown() async instance method.
// XCTest calls it after each test method.
// Perform any asynchronous per-test cleanup here.
}
Then I have a small test, the result is this tearDown() async throws
method is called after test case execution, but print code in DispatchQueue print("~ make an API call")
is never executed, and the test is completed soon. Although I think this method is designed to handle async scenario from what Apple doc said, for instance cleaning server data with API call.
override func tearDown() async throws {
DispatchQueue.main.asyncAfter(deadline: .now() 2) {
print("~ make an API call")
}
}
// tearDown test method
func testDemo() {
print("~ Test started")
}
Thus, my question is what is the property way to clean test data asynchronously in tearDown method?
CodePudding user response:
The problem is that you are mixing an old-style DispatchQueue
-based async method with the new, language feature, async
method.
From the type systems perspective, DispatchQueue.main.asyncAfter
is a sync method, since it isn't marked as async
, hence when you call it from an async
method, the async
method will treat is as a synchronous method and continue execution right after that method returns, rather than waiting for its completion to be executed asynchronously.
You can resolve this issue several ways. You can either wrap the completion-based DispatchQueue.asyncAfter
method in a Continuation
and hence turn it into an actual async
method or you can simply use Task.sleep
.
override func tearDown() async throws {
try await Task.sleep(for: .seconds(2))
// make the API call here
}