18
7

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 5 years have passed since last update.

iOSSnapshotTestCaseを使ったユニットテスト

Posted at

最近テスト書かなきゃという謎の焦燥感が高まっております🔥
そんな折iOSSnapshotTestCaseなるものの存在を知ったので使い方をまとめます✊

iOSSnapshotTestCaseとは

https://github.com/uber/ios-snapshot-test-case
テスト対象のUIViewまたはCALayerのスナップショットを撮り、あらかじめ用意しておいた参考画像と比較し、一致するか確認するテスティングフレームワークです。
参考画像を生成することもできるので、必ずしも事前に参考画像を用意する必要はありません。
これを使うことで、いろんなパターンのビューの画像を生成したり、リグレッションテストを実施することができます。

使い方

インストール

CocoaPodsでインストールできます。
テストのターゲットにiOSSnapshotTestCaseを追加します。

例えばこんな風に
target "プロジェクトTests" do
  use_frameworks!
  pod 'iOSSnapshotTestCase'
end

画像の置き場を設定

比較あるいは生成した参考画像、テストが失敗したときの画像を置く場所を設定します。
いつくか方法があるみたいですが、READMEに載っているやり方だとSchemeの環境変数に以下を定義してやります。
もしディレクトリのパスやターゲットの名前を変更している場合は、適宜合わせてください。
ディレクトリが存在しない場合は勝手に生成してくれるので、事前に作っておく必要はありません。

name value
FB_REFERENCE_IMAGE_DIR $(SOURCE_ROOT)/$(PROJECT_NAME)Tests/ReferenceImages
IMAGE_DIFF_DIR $(SOURCE_ROOT)/$(PROJECT_NAME)Tests/FailureDiffs

Edit Schemeを選んで、
スクリーンショット 2018-09-26 22.07.32.png

RunのArgumentsにあるEnvironment Variablesに書きます。
スクリーンショット 2018-09-26 22.08.56.png

Testじゃなくていいの?と思われるかもしれませんが、デフォルトでRunの設定を引き継ぐようになっているようです。もちろんチェックを外してTestだけに書いてもらっても構わないと思います。
スクリーンショット 2018-09-26 22.09.08.png

テスト記述

クラス定義

FBSnapshotTestCaseを継承したクラスを定義します。FBSnapshotTestCaseXCTestCaseのサブクラスです。

テストファイル上の方
import XCTest
import FBSnapshotTestCase
@testable import SwiftTest // 適宜プロジェクトに合わせて置き換える

class SomeViewTests: FBSnapshotTestCase {
...

setup

setUp()recordModeの設定をします。参考画像を生成したい場合はtrue、既にある参考画像と比較を行う場合はfalseを入れます。

setUp
...
class SomeViewTests: FBSnapshotTestCase {

    override func setUp() {
        super.setUp()
        self.recordMode = false // or true
    }
...

テストケース

XCTestCaseと同様にtestで始まるメソッドを書いていきます。画像の比較または参考画像の生成にはFBSnapshotVerifyView()を使います。

例えばビューが赤い/青いことのテスト
...
    func testRed() {
        let view = UIView(frame: CGRect(x: 0, y: 0, width: 320, height: 60))
        view.backgroundColor = .red // テストしたい状態にする
        FBSnapshotVerifyView(view)  // 比較 or 参考画像生成
    }

    func testBlue() {
        let view = UIView(frame: CGRect(x: 0, y: 0, width: 320, height: 60))
        view.backgroundColor = .blue // テストしたい状態にする
        FBSnapshotVerifyView(view)   // 比較 or 参考画像生成
    }
...

使用上の注意

シミュレータでないとテストできない

実機を選んだ状態でテストすると、参考画像が見つからない的なエラーでfailします。
テスト実行時はシミュレータを選択した状態にしておきましょう。

サイズが(0, 0)のビューは画像が生成されない

考えてみれば当たり前ですが、recordModetrueにして参考画像を生成する際に、ビューのサイズが(0, 0)だと画像が生成されません。ただし、テストfailのメッセージには画像を生成した旨が表示されます。
参考画像が格納されるディレクトリも生成されないので、一番最初に実行する際には注意が必要です。

使ってみて思ったこと

動作確認にとても良い

従来はアプリを起動して目的の画面に行って目的のビューを見る、ということをデータのパターン分繰り返していました。それがiOSSnapshotTestCaseを使えば、必要なデータだけ用意してrecordMode = trueでテストを実行すれば画像を生成してくれるので、複数パターンあるビューや複数端末サイズでの動作確認がとても楽になりました。

テストの知識がそんなにいらないので楽

モックを作って置き換えてみたいなことは一切せず、ビュー作るだけでいいので、テストに不慣れな人でもすぐ取り組むことができます。

画像の容量が際限なく増えていくのが若干不安

いろんなパターンでビューの画像を取りまくるので、容量もどんどん増えていきます。CIでgit cloneするときに遅くなってしまわないか不安はあります。

おわりに

テストというと難しいもの、というイメージがどうしてもありますが、iOSSnapshotTestCaseを使ったテストは非常に簡単です:tada:
これを足がかりにテストを書きはじめて、iOSSnapshotTestCaseでカバーできない部分があることを知り、モックなどを使う次のステップへ、という風な流れを作りやすいんじゃないでしょうか:smile_cat:
どんどんテスト書いていきましょう!:punch::punch::punch:

18
7
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
18
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?