Quickを使ってSwiftコードのユニットテストを行う - Carthageからの利用

はじめに

iOSのユニットテストを行うのに、標準ですとXCTestがありますが、
最近Quickと呼ばれるテストフレームワークがよく使われ出しました。
XCTestも非常に強力なテストフレームワークですが、初見であったり、他の人が記載したテストコードは中々読みづらかったりします。

QuickはXCTestと比べて見かけ上自然なので、後でメンテがやりやすいです。 実際に記事本文にSampleを載せていますので、是非体感してみてください。

今日はそんなQuickの触り部分を紹介します。

導入

CarthageからFrameworkを導入

Cartfileに以下を入力

github "Quick/Quick"
github "Quick/Nimble"

Carthageのビルド

carthage update --platform iOS

f:id:project-unknown:20180410232224p:plain

同じくBuildPhaseの画面上部の「+」でNew Copy File Phaseを選択。

f:id:project-unknown:20180410232256p:plain

Frameworksを選択して、「Nible.framework」と「Quick.framework」を選択する

f:id:project-unknown:20180410232335p:plain

ProjectファイルのDefine Moduleを設定する

Puroject設定の Build SettingsのDefine ModuleをYESにします。
(図では、今回のQuickの為に設定するものなので、Debugのみにしています)

f:id:project-unknown:20180411210636p:plain

テストコードを書く

今回は、UtilitySpec.swiftというファイルをTestターゲットに追加しました。

f:id:project-unknown:20180411221840p:plain

次に、実際にSampleのQuickテストを書いていきます。

import Quick
import Nimble

@testable import <プロジェクト名>

class UtilitySpec: QuickSpec {
    override func spec() {
        describe("データのInsertテスト") {
            beforeSuite {
                // 全てのテストが始まる前に実行する処理
            }
            beforeEach {
                // テスト(it)が始まる前に毎回実行する処理 
            }
            afterEach {
                // テスト(it)が終わった後に毎回実行する処理 
            }
            afterSuite {
                // 全てのテストが終わった後に実行する処理
            }
            context("空のDBに新規Insert") {
                it("正常系") {
                    expect(<処理等>).to(equal(<比較したい値>))
                }
            }
        }
    }
}

<プロジェクト名>や<処理等>と記載された箇所は適切な物を埋め込んでください。
では、実際に上述のコードのそれぞれの意味を紹介します。

QuickSpec

このコードはQuickの基本形で、クラスはQuickSpecを継承して利用しspec()メソッドの中にテストケースを記載します。

describe, context, it

  • descrribe("")
    • 何のテストを行うのか?(クラスやメソッドの何をテストするのか等)を記載します。
  • context("")
    • どの条件でテストを行うのか?を記載します。
  • it("")
    • 結果はどうなるのが正しいのか?を記載します。

※describe, context, itは省略してもOKです。

beforeSuite, beforeEach, afterEach, afterSuite

  • beforeSuite
    • 全てのテストが始まる前に行う処理を記載
  • beforeEach
    • それぞれのテストが始まる前(itが始まる前)に行う処理を記載
  • afterEach
    • それぞれのテストが終わった後(itの後)に行う処理を記載
  • afterSuite
    • 全てのテストが終わった後に処理を記載

expect

expect(<処理等>).to(equal(<比較したい値>))

expectの引数にテスト対象の処理(メソッド呼び出し)や、変数を記載し、
それの結果がtoの引数の中のものになるか?と言う意味になります。
この場合は、equal(<比較したい値>)としていますので、比較したい値と同じかを見ています。

例えば、具体的に、calc()メソッドを呼び出し、その戻り値が2だった場合の書き方です。

expect(calc()).to(equal(2))

テストの実行

テストを実行します。
実行するには、 ⌘ + U で実行するか、以下のようにクラスの先頭のマークをクリックします。

f:id:project-unknown:20180512012305p:plain

以下は上記のテストケースの実行結果です。

Test Case '-[<プロジェクト名>.UtilitySpec データのInsertテスト__空のDBに新規Insert__正常系]' started.
Test Case '-[<プロジェクト名>.UtilitySpec データのInsertテスト__空のDBに新規Insert__正常系]' passed (0.042 seconds).

最後に

今開発中のアプリが仕上げ段階に入り、ユニットテストを本格的に書き始めたので、Quickでテストコードを記載したのですが、やはり書いた後のコードが見やすくて良いですね。
XCTestで慣れている場合は、最初書き方の独特さに躓くかもしれませんが、実際にコードを書いて管理しだすと、非常にメンテがし易いのでおすすめです。