14

The documentation for XCTest waitForExpectationsWithTimeout:handler:, states that

Only one -waitForExpectationsWithTimeout:handler: can be active at any given time, but multiple discrete sequences of { expectations -> wait } can be chained together.

However, I have no idea how to implement this, nor can I find any examples. I'm working on a class that first needs to find all available serial ports, pick the correct port and then connect to the device attached to that port. So, I'm working with at least two expectations, XCTestExpectation *expectationAllAvailablePorts and *expectationConnectedToDevice. How would I chain those two?

Elise van Looij
  • 4,162
  • 3
  • 29
  • 52

5 Answers5

7

I do the following and it works.

expectation = [self expectationWithDescription:@"Testing Async Method Works!"];

[AsynClass method:parameter callbackFunction:^(BOOL callbackStatus, NSMutableArray* array) {
    [expectation fulfil];
    // whatever
}];

[self waitForExpectationsWithTimeout:5 handler:^(NSError *error) {
    if (error) {
        XCTFail(@"Expectation Failed with error: %@", error);
    }
    NSLog(@"expectation wait until handler finished ");
}];

// do it again

expectation = [self expectationWithDescription:@"Testing Async Method Works!"];

[CallBackClass method:parameter callbackFunction:^(BOOL callbackStatus, NSMutableArray* array) {
    [expectation fulfil];
    // whatever
}];

[self waitForExpectationsWithTimeout:5 handler:^(NSError *error) {
    if (error) {
        XCTFail(@"Expectation Failed with error: %@", error);
    }
    NSLog(@"expectation wait until handler finished ");
}];
iceman
  • 181
  • 1
  • 7
3

swift

let expectation1 = //your definition
let expectation2 = //your definition

let result = XCTWaiter().wait(for: [expectation1, expectation2], timeout: 10, enforceOrder: true)

if result == .completed {
    //all expectations completed in order
} 
Ted
  • 22,696
  • 11
  • 95
  • 109
  • 2
    The technique has finally caught up with the documentation. I've been been using this in Objective-C as well and it really works. – Elise van Looij Dec 28 '17 at 16:20
2

Assigning my expectation to a weak variable worked for me.

Bhargav Rao
  • 50,140
  • 28
  • 121
  • 140
Carien van Zyl
  • 2,853
  • 22
  • 30
0

This seems to be working for me in Swift 3.0 as well.

let spyDelegate = SpyDelegate()
var asyncExpectation = expectation(description: "firstExpectation")
spyDelegate.asyncExpectation = asyncExpectation
let testee = MyClassToTest(delegate: spyDelegate)
testee.myFunction() //asyncExpectation.fulfill() happens here, implemented in SpyDelegate

waitForExpectations(timeout: 30.0) { (error: Error?) in
    if let error = error {
        XCTFail("error: \(error)")
    }
}

asyncExpectation = expectation(description: "secoundExpectation")
spyDelegate.asyncExpectation = asyncExpectation
testee.delegate = spyDelegate
testee.myOtherFunction() //asyncExpectation.fulfill() happens here, implemented in SpyDelegate

waitForExpectations(timeout: 30.0) { (error: Error?) in
    if let error = error {
        XCTFail("error: \(error)")
    }
}
choofie
  • 2,575
  • 1
  • 25
  • 30
0

Within a class that extends XCTestCase you can use wait(for:timeout:) like this:

let expectation1 = self.expectation(description: "expectation 1")
let expectation2 = self.expectation(description: "expectation 2")
let expectation3 = self.expectation(description: "expectation 3")
let expectation4 = self.expectation(description: "expectation 4")

// ...
// Do some asyc stuff, call expectation.fulfill() on each of the above expectations.
// ...

wait(for:[expectation1,expectation2,expectation3,expectation4], timeout: 8)

kaylanx
  • 908
  • 1
  • 8
  • 11