I need to perform multiple calls before letting the test()
method run. I have a completion block, and I'm using waitForExpectations()
. Since there is more than one async calls I'm using a counter. I let the expectation.fulfill()
happen only when the counter reaches the number of calls.
override func setUp() {
super.setUp()
let exp = expectation(description: "waitForSetUp")
var counter = 0
// Issue an async request
self.addEventToCalendar(title: "Test1", description: "Description test1", startDate: NSDate().addingTimeInterval(-36000), endDate: NSDate()){(success, error) in
if (success) && (error == nil) {
counter = counter + 1
if(counter == 2){exp.fulfill()}
}
}
self.addEventToCalendar(title: "Test2", description: "Description test2", startDate: NSDate(), endDate: NSDate().addingTimeInterval(36000)){(success, error) in
if (success) && (error == nil) {
counter = counter + 1
if(counter == 2){exp.fulfill()}
}
}
waitForExpectations(timeout: 40, handler: nil)
}
This construction does not work. The test()
method is sometimes run before the calls have returned (not always).
How can I make setUp()
wait for returning multiple async calls?
I had a similar case. The solution that I end up doing was calling several functions, which add expectations for my prerequisites and setting the timeouts for the expectations to a reasonable values. In the completion handlers of the expectations I triggered the next step of my setup algorithm. After all preliminary steps pass I start the actual testing logic.
Attaching link to the Apple Docs.
EDIT: Please see the example code below :
class CommonTests: XCTestCase {
var validate: XCTestExpectation? = nil
func testMytest() {
validate(completion: {
loadSomeStuff(completion: { (list: [Stuff]?) in
// actual test
}
})
}
func validate(completion: @escaping ()->()) {
self.validateExpectation = self.expectation(description: "Setup")
// async operation can be fired here
// or if already started from somewhere else just wait for it to complete
self.waitForExpectations(timeout: 60) { (error: Error?) in
XCTAssert((error == nil), error?.localizedDescription ?? "Failed with unknown error")
completion()
}
}
func validateAsyncCompleted() {
self.validateExpectation?.fulfill()
}
func loadStuff(completion: @escaping ([Stuff]?)->()) {
// possible place for assertion or some other checks
let expectation = self.expectation(description: "loading")
DispatchQueue.global().async {
let result: [Stuff]? = nil
// load operation
expectation.fulfill()
completion(result)
}
self.waitForExpectations(timeout: 90) { (error: Error?) in
XCTAssert((error == nil), error?.localizedDescription ?? "load - failed with unknown error")
}
}
}
NOTE : There are 2 approaches for the expectations, the first expectation is saved in a variable, so it can be fulfilled from another function if needed, the other is created locally in a function body and fulfilled from a closure.