post Image
iOSで非同期処理のテスト: XCTestExpectationの設定値と使い方まとめ

XCTestExpectationの基本の使い方

XCTestExpectationXCTest フレームワークで非同期処理をテストする際に用いられます。基本の使い方は以下の通り、非同期処理を行う関数のコールバック内で 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)
}

『 Swift 』Article List
Category List

Eye Catch Image
Read More

Androidに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

AWSに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Bitcoinに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

CentOSに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

dockerに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

GitHubに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Goに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Javaに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

JavaScriptに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Laravelに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Pythonに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Rubyに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Scalaに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Swiftに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Unityに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Vue.jsに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

Wordpressに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Eye Catch Image
Read More

機械学習に関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。