1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

XCTestの実行順序を確認する

Last updated at Posted at 2022-08-04

あまり意識したことなかったのですが、XCTestがどのような順序で実行されるかについて、WWDC18の What's New in Testing で語られています。

テストは、デフォルトで名前順に実行される

これを確認するため、以下のようなXcodeプロジェクトを用意しました。

  • 整数と、そのインクリメント機能を持つ Singleton オブジェクトを用意
Singleton.swift
import Foundation

final class Singleton {
    static let object = Singleton()

    private(set) var value: Int = 0

    private init() {}

    func increment() {
        value += 1
    }
}

  • TestCase1TestCase9 までのテストケースを用意し、以下のようなテストコードを実装
TestCase1.swift
import XCTest
@testable import ParallelXCTest

class TestCase1: XCTestCase {

    override func setUpWithError() throws {
    }

    override func tearDownWithError() throws {
    }

    func testExample() throws {
        Singleton.object.increment()
        // 1と"TestCase1"の部分はTestCaseXクラスごとに異なる
        XCTAssertEqual(Singleton.object.value, 1, "TestCase1")
    }
}

このテストを実行してみると、確かに TestCase1TestCase9 の順に実行されました。

ランダムな順番でテストを実行する

Testターゲットのスキーム設定から Test > Info > Options... を開き、 Randomize execution order を有効にします。

この状態でテストを実行すると、テストケースがランダムに実行されます。
実行順に依存するテストため、このようにほとんど失敗してしまいます。

テストを並列実行する

先ほどのスキーム設定で Execute in parallel を有効にすると、テストが並列に実行されます。

また先のWWDCセッションにて、並列実行がどのような単位および環境で実行されるか言及しています。

  • テストの並列実行は、シミュレータのクローンを複数作成することで実現する
    • 各クローンは元のシミュレータの「複製」であるため、クローン間でメモリやストレージへの変更は共有されない
  • テストケース単位で各クローンに分配、あるテストケースが完了したら次のテストケースを実行...という形で実行する

TestCase1TestCase9 を並列実行させてみたところ、このようにシミュレータクローンは4つ作成されましたが、すべてのテストが1つのクローンで実行されてしまいました。

これはテストコードが軽量すぎたためで、負荷の代わりに以下のようなスリープを入れて再度並列実行させてみました。

Singleton.swift
final class Singleton {
    ...

    func increment() {
        Thread.sleep(forTimeInterval: 1)
        value += 1
    }
}

相変わらずテストは失敗しますが、テストケースが各クローンに分配されて並列実行されていることがわかります。

もうひとつ注目すべきは、Singleton.object.value が各クローンごとに 1, 2, 3... と増え、最後に実行されたテストケースであっても 9 になっていません。これはテストの並列実行が「クローン間でメモリやストレージへの変更は共有されない」ためです。

各テストケース間や実行順序に依存関係がない よう、アプリケーション設計やテストケースの実装が重要であることが理解できるかと思います。

ただ別の見方をすれば、setUpWithError() でSingletonオブジェクト等の値を変更しても tearDownWithError() で元に戻せば、他のクローンや後続のテストケースへは影響を与えないとも言えます。

XCTestの振る舞いを理解しておけば、広範により良いテストコードが書けるのではないかと思います!

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?