Xcode テスト環境を設定する - shirajira/family-account-ios GitHub Wiki

Xcode テスト環境を設定する

はじめに

本稿に記載の ProjectName は,ご自身のプロジェクト名に読み替えてください。

ProjectNameTests

いわゆる単体テスト。
実装したロジックが期待通りに動作するかどうかを確認できる。

一般に,コーディング後にテストを行うウォーターフォール型の開発手法には(使い方次第だが)あまりマッチしない。
外部環境の変化が激しいアプリ開発においては,テスト駆動開発(TDD)を意識すると変化に柔軟な開発ライフが送れることでしょう。

ProjectNameUITests

いわゆる UI テスト。
本稿では扱わない。

実装手順

1. 環境設定

プロジェクト新規作成時に Include Tests にチェックを入れていれば基本的な設定は済んでいると思われるが,一応以下を確認してください。

プロジェクトツリーが以下のようになっていることを確認する。

ProjectNameTests
    ProjectNameTests.swift
    Info.plist

ProjectNameTests 以下に各モジュールのテストを追加していくことになる。(追加方法は後述)
また,最初からバンドルされている ProjectNameTests.swift は特に使用しなくてもよいが,プロジェクトから削除するとダメっぽい。
Info.plist はとりあえずノータッチでOK。

次に,プロジェクト設定 -> TARGETS -> ProjectNameTests -> General -> Testing まで進み,Host ApplicationProjectName になっていることを確認する。
Allow testing Host Application APIs にはチェックを入れる。

関連:
Xcode プロジェクト新規作成

推奨: コードカバレッジを取得

コードカバレッジを取得するには,Edit Scheme... -> Test -> OptionsCode Coverage にチェックを入れ,右のプルダウンで取得対象のターゲットを指定する。
ターゲットは all targets または some targets から選択。
some targets の場合はその下にある + から対象ターゲットを指定してください。

エディタ上にコードカバレッジを表示するには,エディタ右上の設定アイコンをクリックし,Code Coverage にチェックを入れる。
エディタの右側に,その行がテストで実行された回数が表示されるようになる。
命令網羅(C0)のカバレッジを,例えば 85% 以上にするなどの努力目標を設定しておくとよいでしょう。

2. テストの追加方法

ProjectNameTests を右クリックして,New File... -> Unit Test Case Class を選択し,クラス名を入力。
クラス名はテスト対象モジュールに Tests サフィックスをつけたものにするとよいでしょう。
サブクラスは XCTestCase,言語は Swift を指定する。

以下のような記述のファイルが追加される。

import XCTest

class SampleTests: XCTestCase {

    override func setUpWithError() throws {
        // Put setup code here. This method is called before the invocation of each test method in the class.
    }

    override func tearDownWithError() throws {
        // Put teardown code here. This method is called after the invocation of each test method in the class.
    }

    func testExample() throws {
        // This is an example of a functional test case.
        // Use XCTAssert and related functions to verify your tests produce the correct results.
    }

    func testPerformanceExample() throws {
        // This is an example of a performance test case.
        self.measure {
            // Put the code you want to measure the time of here.
        }
    }

}

まず,@testable import ProjectName を追加する。
この記述により ProjectName 内のクラスや関数のテストが実行できるようになる。

import XCTest
@testable import ProjectName  // 追加

class SampleTests: XCTestCase {

    // 中略

}

テストメソッドを追加するには,test をプリフィックスとしたメソッドを必要なだけ追加していけばよい。
テストメソッドの書き方については後述する。

import XCTest
@testable import ProjectName

class SampleTests: XCTestCase {

    // 正常系のテスト
    func testSampleValidCase() {
        // ...
    }

    // 異常系のテスト
    func testSampleInvalidCase() {
        // ...
    }

}

各テストの前処理および後処理が必要であれば,setUp()tearDown() あたりをオーバーライドすればよい。
これらは各テストメソッド実行前と実行後にコールされる。

import XCTest
@testable import ProjectName

class SampleTests: XCTestCase {

    // 前処理
    override func setUp() {
        // ...
    }
    override func setUpWithError() throws {
        // ...
    }

    // 後処理
    override func tearDown() {
        // ...
    }
    override func tearDownWithError() throws {
        // ...
    }

    // 正常系のテスト
    func testSampleValidCase() {
        // ...
    }

    // 異常系のテスト
    func testSampleInvalidCase() {
        // ...
    }

}

3. テストの実装方法

そのテストが期待通りかどうかは,得られた結果を比較することにより判断できる。

例えば,ある整数を二倍にする関数,

func double(x: Int) -> Int {
    return x * 2
}

をテストするとき,以下のようなアサーションを入れて結果の比較を行えばよい。

func testDouble {
    let y = double(x: 100)  // 実行
    XCTAssertEqual(y, 200)  // 結果の比較
}

ただし,ランダムな入力に対する結果の比較を行ってもそれほど効率は上がらない。
一般に,コーナーケースや条件分岐が発生しそうな入力を重点的にテストする。

このテストフレームワークを活用するためには必然的にテスタビリティの高い設計が求められる。
最初からテストすることを想定した実装(入出力)仕様にしておくことが運用上望ましい。

4. テストの実行

テストメソッド単体,そのクラスのテストメソッドすべて,または ProjectNameTests 内のテストすべてを実行することができる。

メソッドやクラスを単体で実行したい場合,そのメソッドやクラスが定義されている行番号の菱形をクリックする。
また,ProjectNameTests 内のテストをすべて実行したい場合は,メニューバーの Product -> Test または command + U により実行できる。

テストのサマリは Xcode 左メニューの Report navigator(右端)で確認できる。