[Swift]非同期通信のUnit Test

Posted on

非同期処理をするときに戻ってきた値をテストする方法の話 expectationとwaitForExpectations(https://developer.apple.com/documentation/xctest/xctestcase/1500748-waitforexpectations)を使う

XCTestでこんな感じで書くとテストが通ってしまう

import XCTest

func testAsynchronousFunction() {
    asynchronousFunction { (name) in
        XCTAssertEqual(name, "rocky")
        XCTAssertEqual(name, "rocky3") // testされない. test全体としてsucceededに見えてしまう
    }
}

func asynchronousFunction(_ completionHandler: @escaping (String) -> Void) -> Void {
    let queue = DispatchQueue.global()
    queue.async {
        Thread.sleep(forTimeInterval: 1)
        completionHandler("rocky")
    }
}

やる場合には、expectationを作っておいて、callback内でfulfill()を呼んであげて、呼ばれなければテストが失敗するようにする

import XCTest

func testAsynchronousFunction() {
        let functionAnswered = expectation(description: "asynchronous function")
        asynchronousFunction { (name) in
            XCTAssertEqual(name, "rocky")
            XCTAssertEqual(name, "rocky3") // 想定通り、testがfailする
            functionAnswered.fulfill()
        }
        waitForExpectations(timeout: 3, handler: nil) //すべてのexpectationがfulfillされるまで待つ.timeoutは3秒
    }

    func asynchronousFunction(_ completionHandler: @escaping (String) -> Void) {
        let queue = DispatchQueue.global()
        queue.async {
            Thread.sleep(forTimeInterval: 1)
            completionHandler("rocky")
        }
    }

外部API叩くときなんかはmockして実装したところのテストにフォーカスすべきではあるが、こういうのが使いたいときもある

waitForExpectationsで待つ分、多様するとテスト時間が長くなって良くない