Androidアプリの共通コンポーネントに対してVisual Regression Testの導入を検討してみる

本稿はJCB Tech Blog Advent Calendar 2022の12月21日の記事です。

JCB デジタルソリューション開発部 アプリチームの服部です。

この記事では、 私が担当しているAndroidアプリの共通コンポーネントに対してVisual Regression Testの導入が可能か検討した内容について紹介したいと思います。

Visual Regression Testとは

Visual Regression Test(以下、VRT)とはテストの手法の1つです。アプリケーション内の画面や共通コンポーネントを画像として保存しておき、変更が入ったタイミングで再度画像を取得し、新旧比較することで、アプリケーションに意図せぬ変更が生じていないかテストするものです。

VRTの導入を検討した背景

現在、私が担当しているAndroidアプリではUIツールキットとして、Jetpack Composeを採用しており、UI部分については以下のようなモジュール構成となっています。

モジュール 概要
main 各featureモジュールへの参照を持ち、アプリケーションの各画面を統括するモジュール
feature アプリケーションの機能単位に分割されたモジュール
core 各featureモジュールから参照されるアプリケーション全体で共通的に利用できるコンポーネントやデザインテーマを持つモジュール

上記表の通り、アプリケーションで共通的に利用するヘッダーやボタン等の画面コンポーネントはcoreモジュールに定義されており、各featureモジュールで利用します。 各画面で共通コンポーネントを再利用することで開発生産性は上がる一方で、特定画面への改修のつもりが意図せず他画面にも影響するといったリスクもあります。実際に私が担当しているAndroidアプリにおいても、共通コンポーネントの改修によって意図せぬ変更が発生することもありました。

開発初期では、レビューや手動での検証により無影響確認ができるものの、開発が進むに連れて人手で意図しない変更を防ぎながらコードも改修していくことは困難です。

このような背景からVRTによる無影響確認が可能か検討することとしました。

検証時に利用したライブラリ

実際にVRTを検証するにあたって、以下のライブラリを利用しました。各ライブラリのバージョンや概要については以下の通りです。

ライブラリ バージョン 概要
Showkase 1.0.0-beta13 @PreviewがついたComposableをUIカタログ化する。またVRTを行うためのテストコードの生成も行う。
Shot 5.13.0 スクリーンショットライブラリでJetpack Compomseにも対応。画像の差分をレポートを出力する機能も持つ。

事前準備

事前準備としてShowkaseShotの導入するため、build.gradleを修正します。

  buildscript {
    dependencies {
      classpath 'com.karumi:shot:5.13.0'
    }
  }
plugins {
    id 'shot'
}

defaultConfig {
    testInstrumentationRunner "com.karumi.shot.ShotTestRunner"
}

implementation "com.airbnb.android:showkase:1.0.0-beta13" 
kapt "com.airbnb.android:showkase-processor:1.0.0-beta13"
androidTestImplementation "com.airbnb.android:showkase-screenshot-testing-shot:1.0.0-beta13"

その後、以下のようにShowkaseのルートクラスとVRTを行う抽象クラスを作成します。

@ShowkaseRoot
class ShowkaseRoot : ShowkaseRootModule
@ShowkaseScreenshot(rootShowkaseClass = ShowkaseRoot::class)
abstract class ShowkaseScreenshotTest : ShotShowkaseScreenshotTest()

VRTの実行

ライブラリの導入や関連クラスの作成といった事前準備が整ったため、実際にVRTを行っていきます。

VRTは上述の通り、画像の新旧比較となるため、まず比較の対象となる旧画像の取得します。

./gradlew :ui:core:executeScreenshotTests -Precord

次に新画像の取得をし、その後新旧画像の比較レポートを出力します。

./gradlew :ui:core:executeScreenshotTests

上記2つのコマンドが正常に実行された後、以下のようなログが出力されるため、レポートファイルであるindex.htmlを確認します。

> Task :ui:core:executeScreenshotTests
🔎  Comparing screenshots with previous ones.ests
✅  Yeah!!! Your tests are passing.30s]
🤓  You can review the execution report here:
       /Users/xxx/sample/app/ui/core/build/reports/shot/verification/index.html

レポートファイルでは、実行したテストケース数や新旧の画像を横並びで確認できます。

このレポートを出力した時点では、新旧の画像を同じタイミングで取得したため、検証結果としては「差分なし」となっています。

そこで次はあえて新旧比較で差分が出るよう共通コンポーネントに修正を加え、レポートを出力します。

レポートのリード文に1 passed and 2 failedと記載があるように差分が発生していること、またFailure reasonに差分内容に関する記述が表示されていることがわかります。

実際に2回目のレポート出力では、共通コンポーネントの文字サイズや画面要素の背景色を変更したのですが、レポートの結果の通り、正しく変更を検知しています。

おわりに

今回の記事では、Jetpack Composeで共通化した画面コンポーネントに対するVRTの導入についてご紹介しました。 上述の通り、ライブラリを用いることで簡単にVRTの導入が可能であるとわかりました。 今回の検証はローカル端末で行いましたが、今後はCIの一環としてVRTを組み込むことを前提に導入を進めたいと思います。

最後になりますが、JCBでは我々と一緒に働きたいという人材を募集しています。 詳しい募集要項等については採用ページをご覧下さい。

©JCB Co., Ltd. 20︎21