Posted at

iOSでswift-snapshot-testingを使う


swift-snapshot-testingとは

iOSのSnapShotテストといえばiOSSnapshotTestCaseが有名ですが、SnapshotTesting(swift-snapshot testing)というライブラリもあります。

この2つには大きな違いがあり、

iOSSnapshotTestCase
swift-snapshot-testing

Objective-Cで書かれている

Swiftで書かれている

対象はView
対象はViewに限らない

特に、『対象はViewに限らない』というところがポイントだと思います。

Snapshotの意味からすれば、こちらが普通ともいえますね。

とはいったものの、まずは画面のSnapshotを撮るために導入を検討するのでは?という観点からセットアップについて書いていきます。

サンプルプロジェクト

swift-snapshot-testing-sample


インストールする

READMEによると、Carthage / CocoaPods / Swift Package Managerに対応しています。

今回はCarthageでインストールする場合を紹介します。

Carthageインストール時のポイントは


  • テストターゲットのみに追加

  • 通常行うcopy-frameworksは行わない

になります。

つまり、テスト時のみ必要なライブラリですので、リリースビルドには含めないようにするということですね。

github "pointfreeco/swift-snapshot-testing" ~> 1.6

READMEの通りにセットアップを進めると、テストターゲットのBuild Phasesは、このようになります。

test_build_phases.png


XCodeを設定する


画像フォルダを設定

Snapshotテストが失敗した際に出力される画像を格納する、フォルダのパスを設定します。

この設定をしなくてもテストは可能なのですが、設定しないとファイルが出力されません。また、このフォルダは .gitignore に追加し、リポジトリには含めないようにしておきます。

edit_scheme2.png

SchemeのEnviroment Variablesに以下を追加します。

[Name] SNAPSHOT_ARTIFACTS

[Value] $(SOURCE_ROOT)/$(PROJECT_NAME)Tests/__Snapshots__/Failure


シミュレータ起動時の言語を設定

ローカル環境でSnapshotテストが通ったので、意気揚々とPushしたところ、CIでテストがコケるという現象が発生しました。CIから失敗時の画像をダウンロードして確認してみたところ、フォントが微妙に違っていました。

私の開発環境は日本語の設定ですが、CIではOSが素の状態でインストールされた状態なので、システムフォントが異なってしまうのが原因のようです。

シミュレータを日本語で起動することによって、解決できました。

edit_scheme1.png

SchemeのArguments Passed On Launchに以下を追加します。

-AppleLanguages (ja)

※アプリにより状況が異なると思いますので、必要に応じて対応してください


リファレンス画像を出力する


HomeSnapShotTests.swift

func testHomeViewController() {

record = false

let storyboard = UIStoryboard(name: "Home", bundle: nil)
let vc = storyboard.instantiateInitialViewController()!

SnapshotDevices.allCases.forEach {
assertSnapshot(matching: vc, as: .image(on: $0.config), named: $0.name)
}
}


record = true

にするとリファレンス画像が書き出されます。

また、場所の指定はできないようで、テストクラスと同じディレクトリに書き出されます。

project_dir.png

リファレンス画像の命名規則は、下記のようになります。

__Snapshots__/テストクラス名のフォルダ/テストケース名.{named:に渡した名前}.png


テストを実行する

ユニットテストの一環として実行されます。シミュレータの端末を選択し、コマンド+Uです。

READMEによると “単一のシミュレータからすべてのSnapshot画像を生成する” とのことなのですが、テスト時に選択された端末によって得られる画像が異なるようです。特にノッチのあり/なしで余白的な部分が変わりました。これは、リファレンス用のSnapshot画像を撮った端末とテスト時の端末が異なるとテストが失敗してしまうことを意味しています。

Snapshotテスト導入後は、ユニットテスト時の端末を統一するようにしました。

また、CIでのテストも、同じ端末を指定しておく必要があります。


画像のDiff

swift-snapshot-testingはテスト失敗時の差分画像を出力してくれません。

差分を比較したい場合は、Kaleidoscopeを使っています。2枚の画像を並べたり、重ねて違いを表示したりできます。

Two-Up
Difference

スクリーンショット 2019-10-06 13.51.38.png
スクリーンショット 2019-10-06 13.51.44.png

個人的には長年アプリケーションフォルダで眠っていたKaleidoscopeが、活躍する日が来てくれてうれしいです。


最後に

この記事のとおり導入はそれほど難しいものではありません。アプリをより良くしていこうとSnapshotテストの導入を検討している方々の参考になれば幸いです。