swiftunit-testingxctestxctestexpectation

What if XCTestExpectation is unexpected


I'm writing an XCTest unit test in Swift. The idea is that a callback mustn't be called in a certain case.

So what I do, is

func testThatCallbackIsNotFired() {

    let expectation = expectationWithDescription("A callback is fired")
    // configure an async operation

    asyncOperation.run() { (_) -> () in
        expectation.fulfill()    // if this happens, the test must fail
    }

    waitForExpectationsWithTimeout(1) { (error: NSError?) -> Void in

        // here I expect error to be not nil,
        // which would signalize that expectation is not fulfilled,
        // which is what I expect, because callback mustn't be called
        XCTAssert(error != nil, "A callback mustn't be fired")
    }
}

When the callback is called, everything works fine: it fails with a message "A callback mustn't be fired" which is exactly what I need.

But if expectation hasn't been fulfilled, it fails and says

Asynchronous wait failed: Exceeded timeout of 1 seconds, with unfulfilled expectations: "Callback is fired".

Since a not fulfilled expectation is what I need, I don't want to have a failed test.

Do you have any suggestions what can I do to avoid this? Or, maybe, I can reach my goal in a different way? Thanks.


Solution

  • I had this same problem, and I am annoyed that you can't use a handler to override the timeout fail of waitForExpectationsWithTimeout. Here is how I solved it (Swift 2 syntax):

    func testThatCallbackIsNotFired() {
        expectationForPredicate(NSPredicate{(_, _) in
            struct Holder {static let startTime = CACurrentMediaTime()}
    
            if checkSomehowThatCallbackFired() {
                XCTFail("Callback fired when it shouldn't have.")
                return true
            }
    
            return Holder.startTime.distanceTo(CACurrentMediaTime()) > 1.0 // or however long you want to wait
            }, evaluatedWithObject: self, handler: nil)
        waitForExpectationsWithTimeout(2.0 /*longer than wait time above*/, handler: nil)
    }