SwiftのモックライブラリCuckoo

2年ぶりくらいにiOSプロジェクトやってます。

Swiftのモックライブラリで良さそうなのを見つけたので紹介します。

簡単に言うとSwift版Mockitoです。

ちょっと設定とかややこしい部分あるので、そのあたりも含めて簡単に紹介します。

Cuckooインストール

今回はCarthageでインストールします。Quickと同じインストールの方法でやります。

Carthage

Cartfile.private というファイルを作って以下のようにします。

github "SwiftKit/Cuckoo"

で、インストールします。

$ carthage update --platform iOS

Build Phases

XcodeでテストターゲットのBuild Phasesの Link Binary With Libraries にFrameworkを追加します。

Link Binary With Libraries

次に左上の+ボタンから New Copy Files Phase を選択します。 DestinationFrameworks にして、CuckooのFrameworkを選択します。

Copy Files

設定

ちょっとここからが特殊です。GitHubのドキュメントとは少しやり方変えてます。スクリプトの引数にファイルを指定するのではなく、Input Filesを使うようにしています。

Run Script

テストターゲットのBuild Phasesから New Run Script Phase を選択します。そして次のようなスクリプトを設定します。 CuckooSampleTestsの箇所は適宜変更してください。

OUTPUT_FILE="$PROJECT_DIR/CuckooSampleTests/GeneratedMocks.swift"
Carthage/Checkouts/Cuckoo/run generate --testable "$PROJECT_NAME" \
--output "${OUTPUT_FILE}"

Input Files

次に先程追加したScriptの Input Files の箇所にモックを作りたいSwiftのファイルを指定します。

Run Script

Mockファイル生成

ここで一度テストを実行します。最初の実行で依存関係とかを解決してるので、しばらく時間かかります。

完了すると、GeneratedMocks.swift というファイルがテストディレクトリに生成されてるので、それをXcodeに追加します。

ここで設定が終わりです。

使い方

簡単なサンプルで使い方を紹介します。

モック対象コード

単純なprotocolのモックを作ります。(Run ScriptのInput Filesに追加するのを忘れずに)

class UserRepository {
func getName(id: Int) -> String {
return "name"
}

func getAge(id: Int) -> Int {
return 20
}
}

モック

モックを作るには対象のclass/protocolのプレフィックスとして Mock をつけたクラスを生成するだけです。

let mock = MockUserRepository()

スタブ

メソッドの振る舞いを変更してみます。

stub(mock) { stub in
when(stub.getName(id: anyInt())).thenReturn("stub name")
when(stub.getAge(id: anyInt())).thenReturn(18)
}
XCTAssertEqual(mock.getName(id: 1), "stub name")
XCTAssertEqual(mock.getAge(id: 1), 18)

anyInt は引数がどんな数値でも、指定した結果を返すようになります。

thenReturn で振る舞いを変更しています。他にも thenDoNothing とかもあります。

Verify

verifyはメソッドが何回呼ばれたとか、引数が正しいとかを検証することができます。

verify(mock).getName(id: 1)
verify(mock, times(2)).getName(id: 2)

この場合、1行目は引数が1で1回呼ばれたことを検証しています。

2行目は引数が2で2回呼ばれたことを検証しています。

verify(mock, never()).getName(id: anyInt())

never を使うことで、呼ばれてないことも検証できます。

他にも色々使い方あるのですが、詳細はGitHubのほうを確認してみてください。

まとめ

個人的に感じたことを軽くまとめておきます。

AndroidときからMockitoを使ってるので、Cuckooはだいぶ嬉しいです。特にverfiyはよく使ってるので助かります。

ぼくがよく使うケースとしてはprotocolをDIで依存解決してるものを、Mockに置き換えて、verifyで検証するってのをよくやります。

Genericsとかサポートされてないものがありますので注意が必要です。あとはRun Scriptに対象のファイルを追加するのが面倒ですかね。

あと残念なのがAppCodeでコード補完が効かないことですね。AppCode側の問題だと思いますが、コード補完が効くようになることを願ってます。

まだ使い始めたばかりですが、だいぶ便利だと思います。