Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
19
Help us understand the problem. What is going on with this article?
@ktanaka117

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

More than 1 year has passed since last update.

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)
}
19
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ktanaka117
百合好きのダンボールの人です。 SwiftでiOSアプリを開発していて、最近のホットトピックはテスト、設計、リファクタリング。 Twitter: @ktanaka117

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
19
Help us understand the problem. What is going on with this article?