LoginSignup
3
2

reg-suitとroborazziを使用したVRTを実装してみる

Posted at

はじめに

こんにちは、こんばんは、佐藤佑哉ことさとゆーです。今回はreg-suitとroborazziを使用したVRTを実装してみようと思います。

動機

最近のインターンでxmlファイルからJetpack Composeへの移行をした際に、Jetpack Composeに入れ替える時、変更前と変更後の画面を目視で比較する必要があるため、レビューなどで漏れてしまうことがありました。これを機に、機械的に分析してヒューマンエラーをなくすための、VRTを触ってみたいと思うようになりました。

使用技術の紹介

この記事で紹介するVRTツールの技術はreg-suitとroborazziです。

roborazziとは

roborazziとは、Android端末を使わずにJVM上でスクリーンショットを撮影することができるライブラリです。スクリーンショットテストライブラリとして開発されており、テスト中に画像のキャプチャを取得し、事前に取得しておいた期待する画面のキャプチャと比較することで検証を行うことができます。
reg-suitを用いたのは、CA.flutterなどでも紹介されていた、

reg-suitとは

reg-suitとは、VRTのためのCLIを提供するCLIであり、現在の画像と以前の画像を比較し、HTMLに差異を検出してくれるため、差分を視覚的に表示することができます。

使用理由

  • reg-suit:
    • CA.flutterの勉強会でこの技術を知り、本番のプロダクトでも使用されるくらいの信頼性と安定性がある
  • roborazzi
    • nowinandroidや他の企業でも採用されており、非常に人気が高い
    • JVM上で動くため、Androidの環境に依存しないテストの実現が可能

実装フロー

今回は、VRTの実装の観点とreg-suitの技術の都合上、以下のように実装していきます。

  • roborazziを使用して、先ほどのスクリーンショットとVRTを行う
    • roborazziの導入
    • スクリーンショットを撮る
    • VRTを行う
  • reg-suitを使用してroborazziで取得したスクリーンショットを使用して、VRTを行う
    • reg-suitの導入
    • roborazziのスクリーンショットの出力先を変更する
    • 手動で変更前のスクリーンショットを入れておく
    • roborazziで変更後のスクリーンショットを撮り、VRTを行う

roborazziを使用して、画面をスクリーンショット

roborazziの依存関係を追加

roborazziは、下記READMEに記載されているものを参考に依存関係を追加しました。

  • roborazziを使用して、先ほどのスクリーンショットとVRTを行う
    • roborazziの導入
    • スクリーンショットを撮る
    • VRTを行う
  • reg-suitを使用してroborazziで取得したスクリーンショットを使用して、VRTを行う
    • reg-suitの導入
    • roborazziのスクリーンショットの出力先を変更する
    • 手動で変更前のスクリーンショットを入れておく
    • roborazziで変更後のスクリーンショットを撮り、VRTを行う

roborazziを使用してスクリーンショットを撮る

次に、roborazziを使用してスクリーンショットを撮ってみましょう。
スクリーンショットができるように、gradle.propertiesで次のプロパティを有効にします。

roborazzi.test.record=true

早速、スクリーショットができるようになったので、簡単なComposableをスクリーンショットしてみましょう。(ソースコードはこちら)

@RunWith(AndroidJUnit4::class)
@GraphicsMode(GraphicsMode.Mode.NATIVE)
@Config(sdk = [33], qualifiers = RobolectricDeviceQualifiers.Pixel7)
class SampleTest {
    @get:Rule
    val composeTestRule = createAndroidComposeRule<ComponentActivity>()

    @Test
    fun sampleTest() {
        composeTestRule.setContent { MaterialTheme { Text("Hello, World!") } }
        composeTestRule.onRoot().captureRoboImage("src/test/screenshots/Sample/sample_test.png")
    }
}

このコードのみで簡単にComposableのスクリーンショットできるのがわかりました。(実際のスクリーンショットはこちら)

sample_test.png

  • roborazziを使用して、先ほどのスクリーンショットとVRTを行う
    • roborazziの導入
    • スクリーンショットを撮る
    • VRTを行う
  • reg-suitを使用してroborazziで取得したスクリーンショットを使用して、VRTを行う
    • reg-suitの導入
    • roborazziのスクリーンショットの出力先を変更する
    • 手動で変更前のスクリーンショットを入れておく
    • roborazziで変更後のスクリーンショットを撮り、VRTを行う

roborazziを使用して、VRTを行う

次に、roborazziを使用して、VRTを行っていきます。

任意の画面をセット

任意のComposableをテストにセットし、変更前の画面のスクリーンショットを取得します。

@RunWith(AndroidJUnit4::class)
@GraphicsMode(GraphicsMode.Mode.NATIVE)
@Config(sdk = [33], qualifiers = RobolectricDeviceQualifiers.Pixel7)
class HomeScreenTest {

    @get:Rule
    val composeTestRule = createAndroidComposeRule<ComponentActivity>()

    @get:Rule //後に説明
    val roborazziRule = DefaultRoborazziRule

    @Test
    fun homeContent_success() {
        val uiState = HomeUiState.Success(
            uncompletedTodos = emptyList(),
            completedTodos = emptyList(),
            categories = listOf(myTaskCategory),
            selectedCategoryId = 1
        )
        val snackBarHostState = SnackbarHostState()
        composeTestRule.setContent {
            MaterialTheme {
                HomeContent(
                    uiState = uiState,
                    /*...*/
                )
            }
        }
        composeTestRule.onRoot().captureRoboImage()
    }
}

次にComposableのレウアウトを変更します。
今回は、適当に空白を入れておきます。

Spacer(Modifier.height(8.dp))

コマンドの入力

以下のコマンドを入力すると、変更前と変更後の画面のスクリーンショットを比較してくれます。
https://github.com/takahirom/roborazzi?tab=readme-ov-file#build-setup

.gradlew compareRoborazziDebug

入力後に次のディレクトリroot_project/module_name/build/outputs/roborazzi/src/*を見てみましょう。すると、スクリーンショットが3枚入っています。

name.png name_actual.png
name_compare.png

変更前と変更後、差分のスクリーンショットを提供してくれているのがわかります。
また、ファイルroot_project/module_name/build/reports/roborazzi/index.html
をみると、以下のローカルサイトを見ることができます。(一部のレイアウトを抜粋)

スクリーンショット 2024-02-14 0.31.28.png

  • roborazziを使用して、先ほどのスクリーンショットとVRTを行う
    • roborazziの導入
    • スクリーンショットを撮る
    • VRTを行う
  • reg-suitを使用してroborazziで取得したスクリーンショットを使用して、VRTを行う
    • reg-suitの導入
    • roborazziのスクリーンショットの出力先を変更する
    • 手動で変更前のスクリーンショットを入れておく
    • roborazziで変更後のスクリーンショットを撮り、VRTを行う

reg-suitを使用してVRTを行う

reg-suitの導入

reg-suitを本プロジェクトで導入するために次のコマンドを入力します。

$ reg-suit init

初期化が終わると、reg-suitの設定が始まります。

? Working directory of reg-suit. .reg # reg-suitのワーキングディレクトリのディレクトリ名を決定
? Append ".reg" entry to your .gitignore file. Yes
? Directory contains actual images. directory_contains_actual_images //変更後の画面のスクリーンショットのディレクトリ先
? Threshold, ranges from 0 to 1. Smaller value makes the comparison more sensitive. 0 ## デフォルトは0
[reg-suit] info Set up reg-notify-github-plugin:
? notify-github plugin requires a client ID of reg-suit GitHub app. Open installation window in your browser Yes ## reg-notify-github-pluginを使用するために、リポジトリのClientIDが必要
? This repositoriys client ID of reg-suit GitHub app #RepositoryのClientIDを記入

上記のreg-suitの設定を完了すると、以下のファイルが出来上がってると思います。

root_project/ 
           ├ package.json
           ├ package-lock.json
           ├ regconfig.json
           ├ ...
  • roborazziを使用して、先ほどのスクリーンショットとVRTを行う
    • roborazziの導入
    • スクリーンショットを撮る
    • VRTを行う
  • reg-suitを使用してroborazziで取得したスクリーンショットを使用して、VRTを行う
    • reg-suitの導入
    • roborazziのスクリーンショットの出力先を変更する
    • 手動で変更前のスクリーンショットを入れておく
    • roborazziで変更後のスクリーンショットを撮り、VRTを行う

roborazziのスクリーンショットの出力先を変更する

reg-suitでは、スクリーンショットの機能はないため、roborazziを使用して補完します。

## RoborazziRule.Options.outputDirectoryPathでアウトプット先を変更することができる。
roborazzi.record.filePathStrategy=relativePathFromRoborazziContextOutputDirectory

## ファイル名をクラス名.メソッド名.pngと統一することができる
roborazzi.record.namingStrategy=testClassAndMethod

RoborazziRuleを使用して、スクリーンショットの出力先をreg-suit導入時に入れたディレクトリ先を記入します。

val DefaultRoborazziRule =
    RoborazziRule(RoborazziRule.Options(outputDirectoryPath = "../../actual_images"))

@get:Rule
val roborazziRule = DefaultRoborazziRule

現在は、Featureモジュール上でVRTを行っているためこのようにしておりますが、他のモジュール(designsytemmモジュールなど)階層が違うモジュールのVRTを行う際には、VRT専用のモジュールでも作ると、よりこのRoborazziRuleの汎用性が高まりそうだなと記事を書きながら気づきました。

  • roborazziを使用して、先ほどのスクリーンショットとVRTを行う
    • roborazziの導入
    • スクリーンショットを撮る
    • VRTを行う
  • reg-suitを使用してroborazziで取得したスクリーンショットを使用して、VRTを行う
    • reg-suitの導入
    • roborazziのスクリーンショットの出力先を変更する
    • 手動で変更前のスクリーンショットを入れておく
    • roborazziで変更後のスクリーンショットを撮り、VRTを行う

手動で変更前のスクリーンショットを入れておく

reg-suitでは、変更前のスクリーンショットを.reg/expectedに追加されている必要があるため、手動でスクリーンショットを入れておきます。

  • roborazziを使用して、先ほどのスクリーンショットとVRTを行う
    • roborazziの導入
    • スクリーンショットを撮る
    • VRTを行う
  • reg-suitを使用してroborazziで取得したスクリーンショットを使用して、VRTを行う
    • reg-suitの導入
    • roborazziのスクリーンショットの出力先を変更する
    • 手動で変更前のスクリーンショットを入れておく
    • roborazziで変更後のスクリーンショットを撮り、VRTを行う

roborazziで変更後のスクリーンショットを撮り、VRTを行う

roborazziから変更後のスクリーンショットを撮っておきます。

./gradlew recordRoborazziDebug # ./actual_imagesにスクリーンショットが出力される

次に以下のコマンドを入力し、reg-suitによるVRTを行います。

reg-suit run

これをすると、以下のディレクトリが自動生成されます

.reg/
   ├ actual/ # 変更後のスクリーンショットが出力される
   ├ diff/ # 差分
   ├ expeted/ # 手動でスクリーンショットを入れたディレクトリ
   ├ index.html # 差分レポート
   ├ ...

index.htmlはこちらになっております。reg-suitは機能満載で、差分がとてもみやすいサイトになっていました。

スクリーンショット 2024-02-14 1.43.52.png

スクリーンショット 2024-02-14 1.46.02.png

これで、roborazziとreg-suitを使用したVRTを実現することはできました🎉

  • roborazziを使用して、先ほどのスクリーンショットとVRTを行う
    • roborazziの導入
    • スクリーンショットを撮る
    • VRTを行う
  • reg-suitを使用してroborazziで取得したスクリーンショットを使用して、VRTを行う
    • reg-suitの導入
    • roborazziのスクリーンショットの出力先を変更する
    • 手動で変更前のスクリーンショットを入れておく
    • roborazziで変更後のスクリーンショットを撮り、VRTを行う

まとめ

本記事では、reg-suitとroborazziを使用したVRTを実装いたしました。
個人的に実装コストやAndroidアプリ開発における汎用性を考えると、roborazziがかなり使い勝手が良さそうです。インターフェースの細かな調整のレビューが重視される場合は、reg-suitを使用してみるのもありだと感じました!

誰かの開発の助けになれば幸いです🙇‍♂️

3
2
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
3
2