Galapagos Tech Blog

株式会社ガラパゴスのメンバーによる技術ブログです。

Roborazziでスクリーンショットテストを導入した話

サービス開発パートナー事業部 Androidエンジニアの務台です。 最近はモンハンNowのために散歩する日々が続いています。本編では双剣使いだったので早く追加してほしいなぁと思う今日この頃です。


皆さんのプロジェクトではスクリーンショットテストは使っていますか?

私が担当しているプロジェクトでは今までやってこなかったのですが、満を持して導入することができましたので、 その中での躓きを共有できればと思います。

結論

  • Compose Material3のバージョンが1.0.1未満の場合はgradleへ以下の記述が必要になる
configurations.all {
    resolutionStrategy.force libs.compose.material3
}

UIテスト導入の背景

Compose Material3のバージョンを1.0.0-alpha13から1.0.2に上げたところ…

1.0.0-alpha13 => 1.0.2

はい。HorizontalPagerのインジケータの位置がずれてしまいました。

この変化はたまたま見つけることができましたが、全コンポーネントを目視で確認するのはとても大変ですし、確認漏れが発生する恐れがあります。

このような予期しない変更を検知するため、Material3のバージョンアップ前にUIテストを導入し、バージョンアップによる表示崩れが起きないようにしました。

Roborazziの導入

現在だとUIテストを行うときに使用するライブラリとしては

のいずれかが選択肢として挙がるかと思いますが、今回は以下の理由によりRoborazziを使用することにしました。

  • Paparazziより後発であり、Paparazziで使用できる機能を保有していること
  • Hiltを使用したDIが使用可能であること
  • DroidKaigi 2023アプリに使用されており、この実装を参考にできること

導入手順

導入手順としてはGitHubに書いてあるとおり簡単で、

Robolectricを追加して

testImplementation "org.robolectric:robolectric:4.10.3"

プロジェクトのgradleにプラグインを追加して

plugins {
   id "io.github.takahirom.roborazzi" version "1.6.0" apply false
}

モジュールのgradleにもプラグインを追加する。

plugins {
    id 'io.github.takahirom.roborazzi'
}

./gradlew test実行時にスクリーンショットテストも行うために gradle.propertiesに以下を追記する。

roborazzi.test.verify=true

ここまででライブラリの導入は完了です。

あとはキャプチャの保存先や判定の閾値等を管理するクラスを作成して

class LaunchScreenShotRobot(
    private val composeTestRule: ComposeContentTestRule,
) {
    private val roborazziOptions = RoborazziOptions(
        compareOptions = RoborazziOptions.CompareOptions(
            changeThreshold = 0.001f,
        ),
    )

    fun setupContent(
        content: @Composable () -> Unit,
    ) {
        composeTestRule.setContent {
            MaterialTheme {
                Surface {
                    content()
                }
            }
        }
    }

    fun captureLaunchScreen(
        fileName: String,
    ) {
        composeTestRule.onRoot().captureRoboImage(
            filePath = "screenshots/$fileName.png",
            roborazziOptions = roborazziOptions,
        )
    }
}

スクリーンショットテストを行うためのユニットテストを書く。

@RunWith(AndroidJUnit4::class)
@GraphicsMode(GraphicsMode.Mode.NATIVE)
@Config(
    qualifiers = RobolectricDeviceQualifiers.Pixel7Pro,
    sdk = [33],
)
class SampleScreenShotTest {
    @get:Rule
    val composeTestRule = createComposeRule()

    @Test
    fun checkSampleScreen() {
        with(LaunchScreenShotRobot(composeTestRule)) {
            setupIntegrationContent {
                SampleCompose(modifier = Modifier.fillMaxSize())
            }
            captureLaunchScreen("SampleScreen")
        }
    }
}

これにより./gradlew recordRoborazziDebugスクリーンショットを/screenshots/配下に保管し、 ./gradlew test実行でUIの変更も検知することができるようになります。

…通常であれば、、、

沼った

Roborazziを依存関係へ追加後ビルドすると、プロジェクトで使用しているMaterial3のバージョンが1.0.0-alpha13なのにも関わらず、 上記と同様の位置ズレ問題が発生するようになってしまいました。 これはRoborazziがMaterial3 1.0.1に依存していることが原因でした。(原因調査に1日以上かかってしまった…)

Roborazziでも1.0.0-alpha13を使用すればOKなので、以下の記述をgradleへ追加します。

configurations.all {
    resolutionStrategy.force libs.compose.material3
}

これによってRoborazziでも使用するMaterial3のバージョンが1.0.0-alpha13に強制され、UIが崩れる前のHorizontalPagerの画像を取得することができました。

試してみる

これでMaterial3のバージョンアップ前、バージョンアップ後でスクリーンショットテストによるUI崩れの検知ができるようになったはずなので試してみます。

バージョンアップ前に./gradlew recordRoborazziDebugを実行し、 バージョンアップ後に./gradlew testを実行してみると…

Roborazzi: /screenshots/Sample.png is changed.

無事、テストに失敗しました。 build/outputs/Roborazzi/Sample_compare.pngを見てみると

と、しっかり差分が検知されていることが確認できます。

まとめ

躓きはあったものの、無事Roborazziによるスクリーンショットテストを導入し、Material3のバージョンアップによるUI崩れを検知することができるようになりました。 一度入れてしまえばあとは新画面追加の度にスクリーンショットテストの実装も追加していくだけなので簡単にUI崩れを防ぐことができそうです。

まだまだ使用していないRoborazziの機能があるので、今後は

  • Hiltを利用したRobotのDI
  • ライトモード、ダークモードでのスクリーンショットテスト
  • RoborazziRuleを用いたgifでの動作中画像の比較

あたりを追加できたらいいなと思っています。


ガラパゴスでは、一緒に働く仲間を募集しています!

hrmos.co

DroidKaigi 2023楽しんできました!!

サービス開発パートナー事業部 Androidエンジニアの務台です。

題名にもあるとおり…

DroidKaigi 2023全力で楽しんできました!!!

のでそのご報告です。

DroidKaigiに参加しますの記事はこちら↓ ↓ ↓

techblog.glpgs.com

ブース出展しました

去年に引き続き、Galapagosはスポンサー参加することができましたので、ブースも出展させていただきました。

去年の様子はこちら↓ ↓ ↓

techblog.glpgs.com

弊ブースでは飴ちゃんを配ったり動くbugdroidくんを置いて、一緒にDroidKaigi 2023を盛り上げることができました。

準備をしていただいた皆様、ブースに来ていただいた方々、本当にありがとうございました!

セッションもたくさん見ました

私個人としては二日間で合わせて9つのセッションを見ることができました。どのセッションもとても面白く、今後のエンジニア活動に役立てることができるものばかりでした。わからなかったことは調べて、自分の知識として取り入れていこうと思います!

セッションのまとめとかもブログに書けたらいいなぁ…

他にも

ネイルしたり、

豪華なパーティーでワイワイしたり、

とても、とても楽しかったです!

さいごに

関係者の皆様、本当にありがとうございました!


ガラパゴスでは、一緒に働く仲間を募集しています!

hrmos.co

GalapagosはDroidKaigi 2023を応援しています。

サービス開発パートナー事業部 のiOSエンジニアの亀澤です。電気代が心配な今日この頃です。

DroidKaigi 2023のスポンサー参加します。

今年もDroidKaigiのスポンサー参加できることとなりました。残念ながらiOSDC 2023のスポンサー参加はかなわなかったのですが、参加が決まったDroidKaigiの準備でてんてこ舞いしています。
弊社のロゴや部署名などが変わったので、昨年作ったものが作り直しで必死に準備を進めている真っ最中です。
今回もブース展示を行いますが、前回の反省を元にどのような展示にするか考えています。
イベント自体もたのしみですが弊社はリモートワークが中心となっているので、普段直接会っていない同僚と会えるのも楽しみの一つです。

ドロイド君もバージョンアップして参加予定

DoroidKaigi 2022のブースでお披露目したドロイド君、記事の通りIFTTTBeeBotteを利用してTwitter連携させる予定でした。

改修中のドロイド君
特定のキーワードがツイートされるとそれを検知してダンスするようにしていたドロイド君ですがDrodiKaigi2日目にしてTwitter連携機能を廃止しました。
理由は

  • 無料枠のIFTTTでTwitter Web Hookを使ったがツイートしてから反応するまで2分近くかかる(その後、IFTTTに課金してみたところ改善はしたが30秒はかかる)
  • M5StickがWiFi 2.4GHz帯でしか使えない(会場は5GHzのみ)

と致命的です。
ツイート検知機能の代わりにPIRセンサ(人感センサ)で反応したら動くようにしたのですが準備の時と違い実際には人が多すぎて常にセンサが反応していました。 なんとか一部の方に動く姿をお披露目できましたが納得のいく動きをせず消化不良でした。
今年に入って知人からMakersFairTokyoの出展にも誘われたので、改修版としてセンサを距離センサに変更して近寄ったり離れたりで動きが変わる様に改良しました。 残念ながら枠は落ちてしまいましたが、DoroidKaigiでバージョンアップしたドロイド君をお披露目するつもりですので是非ブースにお立ち寄りください。
それでは皆さんと会場でお会いできるのを楽しみにしています。

ガラパゴスでは一緒に働く仲間を募集しています。 hrmos.co エントリーお待ちしてます!