Handling asynchronous tests

Given the non-blocking asynchronous communication model in most of the server-side frameworks, each test often involves an asynchronous call to an API method. The callback of an asynchronous call contains the results of a test run. This means that the validation of the returned results of a test happen at an undetermined time later. You need to take precautionary measures to ensure that the thread for validating the result doesn't terminate prematurely.

The Kitura test boilerplate code shows you how to handle a non-blocking asynchronous situation elegantly:

func testGetStatic() {
let printExpectation = expectation(description: "The /route will serve static HTML content.") // [1]

URLRequest(forTestWithMethod: "GET")?
.sendForTestingWithKitura { data, statusCode in // [2]
if let getResult = String(data: data, encoding: String.Encoding.utf8){ // [3]
XCTAssertEqual(statusCode, 200)
XCTAssertTrue(getResult.contains("<html"))
XCTAssertTrue(getResult.contains("</html>"))
} else {
XCTFail("Return value from / was nil!")
}
printExpectation.fulfill() // [4]
}

waitForExpectations(timeout: 10.0, handler: nil) // [5]
}

In this code, XCTestCase uses the class XCTestExpectation to help facilitate the communication to you when asynchronous test tasks are complete:

  1. Creates a new expectation
  2. Uses an URLRequest extension function to process the HTTP request/response
  3. Receives the HTTP response result asynchronously
  4. Marks an expectation instance as fulfilled
  5. Waits for the expectation to finish

You use the method expectation(description:) in [1] to create a new expectation with an associated description. The method returns an instance of XCTestExpectation that you can use. The description in the string will be displayed in the test log for this expectation to help diagnose failures.

When the asynchronous tasks in your test are done, call the expectation instance's fulfill() method in [4] to signal that the expectation is fulfilled.

To instruct XCTestCase not to end your test prematurely, you call waitForExpectation(timeout:handler:) in [5] and specify how much time you want to wait.