44

I want to delay progression of a test for T seconds, without generating a timeout.

First I tried the obvious:

sleep(5)
XCTAssert(<test if state is correct after this delay>)

But that failed.

Then I tried:

let promise = expectation(description: "Just wait 5 seconds")
waitForExpectations(timeout: 5) { (error) in
    promise.fulfill()

    XCTAssert(<test if state is correct after this delay>)
}

My XCTAssert() now succeeded. But waitForExpectations() failed with a timeout.

This is according to the documentation of XCTest wait functions saying:

Timeout is always treated as a test failure.

What are my options?

4 Answers 4

84

You can use XCTWaiter.wait functions.

For example:

let exp = expectation(description: "Test after 5 seconds")
let result = XCTWaiter.wait(for: [exp], timeout: 5.0)
if result == XCTWaiter.Result.timedOut {
    XCTAssert(<test if state is correct after this delay>)
} else {
    XCTFail("Delay interrupted")
}
Sign up to request clarification or add additional context in comments.

1 Comment

(1) Where should I call my method to test (2) How to set the expectation as fulfil?
32

If you know how much time something will take and simply want to wait that duration before continuing the test, you can use this one line:

_ = XCTWaiter.wait(for: [expectation(description: "Wait for n seconds")], timeout: 2.0)

Comments

13

What best worked for me was:

let timeInSeconds = 2.0 // time you need for other tasks to be finished
let expectation = XCTestExpectation(description: "Your expectation")

DispatchQueue.main.asyncAfter(deadline: .now() + timeInSeconds) {
    expectation.fulfill()
}    

wait(for: [expectation], timeout: timeInSeconds + 1.0) // make sure it's more than what you used in AsyncAfter call.

//do your XCTAssertions here
XCTAssertNotNil(value)

Comments

0

if you need or prefer to work with async/await you can use something like the following:

    func wait(seconds: TimeInterval) async {
        let expectation = XCTestExpectation(description: "Wait utility")
        DispatchQueue.main.asyncAfter(deadline: .now() + seconds) {
            expectation.fulfill()
        }
        await fulfillment(of: [expectation], timeout: seconds + 1)
    }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.