UIテストをやっていると、アニメーションの実行を待ってからアサートを実行したいときがあります✅
しかし、DispatchQueue
のメソッドを使うと、テストの実行自体が止まってしまってアニメーションが実行されなかったり、アニメーションの完了を待たずにテストが終わってしまったり、メインスレッドでは無いスレッドでは描画ができなかったり、なかなか期待する結果になってくれませんでした😭
この記事では、試行錯誤の結果うまく行った便利メソッドを紹介します💡
もしDispatchQueueでもできるよーってことならぜひコメントにて教えていただけると幸いです🙇
(本当はカスタムトランジションについてまとめようかと思っていたけど、時間が無いのでそれは後日・・・)
ディレイメソッド
XCTestExpectation
というものを使います。
func delay(testCase: XCTestCase, seconds: Float) {
let delay = testCase.expectation(description: "animation finished")
DispatchQueue.main.asyncAfter(deadline: .now() + TimeInterval(seconds)) {
delay.fulfill()
}
testCase.waitForExpectations(timeout: TimeInterval(seconds + 1.0))
}
短いコードですが、各要素を見ていきます。
func delay(testCase: XCTestCase, seconds: Float) {
引数にはテストクラスそのものと、ディレイさせたい秒数を渡します。
let delay = testCase.expectation(description: "animation finished")
まずはXCTestExpectation
を生成します。descriptionは何でもいいです。
DispatchQueue.main.asyncAfter(deadline: .now() + TimeInterval(seconds)) {
delay.fulfill()
}
指定された秒数待ったのち、fulfill()
を呼び出します。これは期待する結果になったよ、ということを通知するためのメソッドです。
アニメーションはこの待ち時間の間に実行されています。秒数はアニメーションと合わせてください。
testCase.waitForExpectations(timeout: TimeInterval(seconds + 1.0))
念の為、指定された秒数よりちょっと多めにfulfill()
が来るのを待ちます。タイムアウトの時間が経過してしまうとテストがFailedになってしまいます。
終わりに
XCTestExpectation
について調べてみたら、APIの取得を待つのに使われている例がいくつか見つかりました🔍
自分はアニメーションを待つために使ったのですが、非同期全般使えるので活躍の機会は多そうです🎉
参考
XCTestExpectation
XCTest入門Part2 (Swift) ~非同期編~
iOS XCTestで非同期処理の完了を待つ