XCTestExpectationの基本の使い方
XCTestExpectation
は XCTest
フレームワークで非同期処理をテストする際に用いられます。基本の使い方は以下の通り、非同期処理を行う関数のコールバック内で fulfill()
を呼び出し、 wait(for:timeout:)
することで、待機するexpectationとそれのタイムアウトを設定します。
func someAsynchronousFunction(completion: () -> ()) {
// do some asynchronous tasks
completion()
}
func testHoge() {
let exp = expectation(description: "Hoge")
someAsynchronousFunction {
// callback
exp.fulfill()
}
wait(for: [exp], timeout: 10.0)
}
fulfill()する回数を指定する
wait(for:timeout:)
で XCTestExpectation
のインスタンスをwaitした場合、 デフォルトで fulfill()
をテスト終了までに一回呼び出さなければなりません。この時、呼び出しが0回でも、2回以上でもテストが失敗します。
// 呼び出し回数が0回で失敗(タイムアウト)
func testHoge() {
let exp = expectation(description: "Hoge")
someAsynchronousFunction {
// callback
}
wait(for: [exp], timeout: 10.0) // <- Asynchronous wait failed: Exceeded timeout of 10 seconds, with unfulfilled expectations: "Hoge".
}
// 呼び出し回数が2回で失敗(複数回fulfillが呼ばれている)
func testHoge() {
let exp = expectation(description: "Hoge")
someAsynchronousFunction {
// callback
exp.fulfill()
exp.fulfill()
}
wait(for: [exp], timeout: 10.0) // <- caught "NSInternalInconsistencyException", "API violation - multiple calls made to -[XCTestExpectation fulfill] for Hoge."
}
もしも複数回の fulfill()
呼び出しを期待するテストが書きたい場合は、 expectedFulfillmentCount
プロパティに期待する呼び出し回数を指定します。
// 呼び出し回数を2回で指定して成功する
func testHoge() {
let exp = expectation(description: "Hoge")
exp.expectedFulfillmentCount = 2
someAsynchronousFunction {
// callback
exp.fulfill()
exp.fulfill()
}
wait(for: [exp], timeout: 10.0)
}
expectedFulfillmentCount
プロパティはデフォルトの値が1です。もしも指定した回数を下回るか、超えてしまう場合はテストが失敗します。
fulfill()の呼び出し回数の上限を無くす
expectedFulfillmentCount
で指定した回数を超えて fulfill()
を呼び出すと、テストが失敗してしまうのは先述した通りです。この呼び出し回数の上限を無くすには assertForOverFulfill
プロパティをfalseにします。
// 呼び出し回数が指定回数を超えても成功する
func testHoge() {
let exp = expectation(description: "Hoge")
exp.expectedFulfillmentCount = 2
exp.assertForOverFulfill = false
someAsynchronousFunction {
// callback
exp.fulfill()
exp.fulfill()
exp.fulfill() // <- expectedFulfillmentCountは2だが、3回目のfulfill()を呼んでもテストは失敗しない
}
wait(for: [exp], timeout: 10.0)
}
assertForOverFulfill
プロパティはデフォルトではtrueになっています。
期待する結果を反転させる
XCTestExpectation
で期待する結果を反転させるには、 isInverted
プロパティをtrueにします。デフォルトはfalseです。
XCTestExpectation
のインスタンスをwaitして、waitしている間に fulfill()
されればテストが成功するというのが通常の挙動です。期待する結果を反転させるというのは、 fulfill()
された場合、テストが失敗するということです。
isInverted
プロパティがtrueで、 fulfill()
を呼び出してテストが失敗した場合、 XCTWaiterDelegate
のメソッドが呼び出されます。( waiter(_ waiter:didFulfillInvertedExpectation expectation:)
)
// 期待する結果を反転させたexpをfulfill()して失敗する
func testHoge() {
let exp = expectation(description: "Hoge")
someAsynchronousFunction {
exp.isInverted = true
exp.fulfill() // <- Fulfilled inverted expectation "Hoge".
}
wait(for: [exp], timeout: 10.0)
}
isInverted
プロパティをtrueにした XCTestExpectation
のインスタンスをwaitして、テストがタイムアウトした場合、テストは成功します。このとき、 XCTWaiterDelegate
のタイムアウト失敗時のdelegateメソッドは呼び出されません。( waiter(_ waiter:didTimeoutWithUnfulfilledExpectations unfulfilledExpectations:)
)
// isInverted = trueとなっているので、タイムアウトしてもテストが成功する
func testHoge() {
let exp = expectation(description: "Hoge")
someAsynchronousFunction {
exp.isInverted = true
}
wait(for: [exp], timeout: 10.0)
}