Simplifying a bit the code structure, I have a UIViewController
with viewDidLoad()
that calls a method that uses DispatchQueue.main.async()
to wait for the main thread to execute the code.
viewDidLoad() {
method()
}
method() {
...
DispatchQueue.main.async() {
...some code...
}
}
My test also need to wait for the main thread before to call XCTAssertEqual.
func testSuccessRequest() {
let exp = expectation(description: "labelText")
let vc = ViewController.init()
vc.request = SuccessRequest.init()
vc.loadViewIfNeeded()
DispatchQueue.main.async() {
XCTAssertEqual(vc.label.text, "success")
exp.fulfill()
}
waitForExpectations(timeout: 40, handler: nil)
}
Is this test robust? Or could I have situations in which the assert code is called before the async?
Since method() is async so while testing if you call
DispatchQueue.main.async() {
XCTAssertEqual(vc.label.text, "success")
exp.fulfill()
}
right after vc.loadViewIfNeeded() you are not guaranteed that test case expectation will get full fill before async method() calls gets completed. Since both calls - method() & above - are async.
But what you can do is - ful fill test case expectation after some time like below:
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
XCTAssertEqual(vc.label.text, "success")
[expectation fulfill];
});
waitForExpectations(timeout: 40, handler: nil)
This is the one way you can test async method which is uses GCD. Hope it helps.
EDIT: While above strategy can make you wait for 2s. There is better method in this scenario we can implement.
We can take help of XCTKVOExpectation and XCTWaiter class available in XCTest framework. Here is the brief descriptions about them:
Now your test case will look like.
func testSuccessRequest() {
let promise = XCTKVOExpectation(keyPath: "text", object: vc.label,
expectedValue: "success")
let vc = ViewController.init()
vc.request = SuccessRequest.init()
vc.loadViewIfNeeded()
let result = XCTWaiter().wait(for: [promise], timeout: 40)
XCTAssertTrue(result == .completed)
}
Here, a KVO exp. is created on "text" properties of label and then view is loaded with async call and then test case wait for some time before time out. Then you can assert the return value from XCTWaiter.
Hope it helps.
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