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は、このようになります。
XCodeを設定する
画像フォルダを設定
Snapshotテストが失敗した際に出力される画像を格納する、フォルダのパスを設定します。
この設定をしなくてもテストは可能なのですが、設定しないとファイルが出力されません。また、このフォルダは .gitignore に追加し、リポジトリには含めないようにしておきます。
SchemeのEnviroment Variablesに以下を追加します。
[Name] SNAPSHOT_ARTIFACTS
[Value] $(SOURCE_ROOT)/$(PROJECT_NAME)Tests/__Snapshots__/Failure
シミュレータ起動時の言語を設定
ローカル環境でSnapshotテストが通ったので、意気揚々とPushしたところ、CIでテストがコケるという現象が発生しました。CIから失敗時の画像をダウンロードして確認してみたところ、フォントが微妙に違っていました。
私の開発環境は日本語の設定ですが、CIではOSが素の状態でインストールされた状態なので、システムフォントが異なってしまうのが原因のようです。
シミュレータを日本語で起動することによって、解決できました。
SchemeのArguments Passed On Launchに以下を追加します。
-AppleLanguages (ja)
※アプリにより状況が異なると思いますので、必要に応じて対応してください
リファレンス画像を出力する
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
にするとリファレンス画像が書き出されます。
また、場所の指定はできないようで、テストクラスと同じディレクトリに書き出されます。
リファレンス画像の命名規則は、下記のようになります。
__Snapshots__/テストクラス名のフォルダ/テストケース名.{named:に渡した名前}.png
テストを実行する
ユニットテストの一環として実行されます。シミュレータの端末を選択し、コマンド+Uです。
READMEによると “単一のシミュレータからすべてのSnapshot画像を生成する” とのことなのですが、テスト時に選択された端末によって得られる画像が異なるようです。特にノッチのあり/なしで余白的な部分が変わりました。これは、リファレンス用のSnapshot画像を撮った端末とテスト時の端末が異なるとテストが失敗してしまうことを意味しています。
Snapshotテスト導入後は、ユニットテスト時の端末を統一するようにしました。
また、CIでのテストも、同じ端末を指定しておく必要があります。
画像のDiff
swift-snapshot-testingはテスト失敗時の差分画像を出力してくれません。
差分を比較したい場合は、Kaleidoscopeを使っています。2枚の画像を並べたり、重ねて違いを表示したりできます。
Two-Up | Difference |
---|---|
個人的には長年アプリケーションフォルダで眠っていたKaleidoscopeが、活躍する日が来てくれてうれしいです。
最後に
この記事のとおり導入はそれほど難しいものではありません。アプリをより良くしていこうとSnapshotテストの導入を検討している方々の参考になれば幸いです。