非同期なAPIのテスト - XCTestExpectation
非同期なAPIをテストする場合は、XCTestExpectation
を用い、処理が完了するまで待機するのが一般的。
テスト対象のサンプルコード。
func echo(message: String, _ handler: @escaping (String) -> Void) { DispatchQueue.global().async { // 3秒待機 Thread.sleep(forTimeInterval: 3) // 終端に「&」をつけてコールバック呼び出し DispatchQueue.main.async { handler(message + "&") } } } // echo() の利用 echo(message: "hoge") { message in XCTAssertEqual(message, "hoge" + "&") // 3病後に実行される }
まずは間違ったテスト処理を示す。
func testEcho() { echo(message: "Hello") { message in XCTAssertEqual(message, "Hello!") } }
この場合、テストは成功してしまう。
なぜ??
それは非同期処理の終了を待たずにテストメソッド自体が終了してしまう、つまりアサーションが実行されないため。
失敗したアサーションがなかったためテストは成功とみなされる。
以下が正しいテストコード!
func testEcho() { // 待機用の XCTestExpectation を生成 let exp: XCTestExpectation = expectation(description: "wait for finish") echo(message: "Hello") { message in XCTAssertEqual(message, "Hello!") // expの待機を解除 exp.fulfill() } // expに対してfulfill()が呼び出されるまで待機(5秒でタイムアウト) wait(for: [exp], timeout: 5) }