📱

Now in AndroidでRoborazziはどのように使われているか

2024/02/07に公開

はじめに

最近、Android のテストについて興味が高まっており色々調べています sanao と申します。
Roborazziとは、@takahirom氏によって開発されているスクリーンショットテストライブラリです(私も地味に Contribute してるぜ)。
その有用性から、now in android にも 2023 年夏ごろに採用されました[1]
本記事では now in android 内で Roborazzi がどのように使われているのかざっくりと説明します。
なお、まだまだ now in android では Roborazzi の導入が進むことが予想されますので、執筆時点(2024/2/6)での情報だということにご注意ください。

本記事では説明しないこと

  • Roborazzi を採用するメリット
  • Roborazzi の使い方

使用箇所

現在、Roborazzi が配置されているモジュールは

  • core/testing
  • core/designsystem
  • app
  • feature/foryou

になります。

core/testing

core/testing では、スクリーンショットをシュッと撮るためのヘルパー関数などが実装されています。
もっともよく使用されている関数がcaptureMultiThemeです。
https://github.com/android/nowinandroid/blob/3ff5d48f3739c2341bfb288779e35ff444015783/core/testing/src/main/kotlin/com/google/samples/apps/nowinandroid/core/testing/util/ScreenshotHelper.kt#L94-L101
captureMultiTheme

  • 出力するスクリーンショットのファイル名
  • ダークモードか
  • ダイナミックカラーを使うか
  • Android テーマを使うか

を引数を変えるだけで柔軟にスクリーンショットを撮影することができます。

また、現状の使用頻度は少ないですが、デバイスごとにスクリーンショットを取得する関数もあります。
まず、ただひとつのデバイスでスクリーンショットを撮影するためのcaptureForDevice関数が実装されています。
https://github.com/android/nowinandroid/blob/3ff5d48f3739c2341bfb288779e35ff444015783/core/testing/src/main/kotlin/com/google/samples/apps/nowinandroid/core/testing/util/ScreenshotHelper.kt#L61-L68
これも同様に引数から

  • 出力するスクリーンショットのファイル名
  • 撮影に使用するデバイスのスペック
  • ダークモードか

を設定できます。
captureForDeviceの引数deviceSpec: String は次のように使われています。

composeTestRule.captureForDevice(
            deviceName = "phone_dark",
            deviceSpec = DefaultTestDevices.PHONE.spec,
            ...

DefaultTestDevices 列挙型はあらかじめ定義してあるスマホ、折りたたみデバイス、タブレットの高さや幅などのスペックです。
以下のように定義されています。
https://github.com/android/nowinandroid/blob/3ff5d48f3739c2341bfb288779e35ff444015783/core/testing/src/main/kotlin/com/google/samples/apps/nowinandroid/core/testing/util/ScreenshotHelper.kt#L47-L51

また、DefaultTestDevices 列挙型を用いてスマホ、折りたたみデバイス、タブレットの全てのスクリーンショットを一括で撮影する関数 captureMultiDevice も実装されています。
https://github.com/android/nowinandroid/blob/3ff5d48f3739c2341bfb288779e35ff444015783/core/testing/src/main/kotlin/com/google/samples/apps/nowinandroid/core/testing/util/ScreenshotHelper.kt#L52-L59

core/designsystem

以上の 6 ファイルにて使用されています。
ほとんどがcaptureMultiThemeでただ撮影しているだけなのですが、LoadingWheelだけ注目すべき実装があったので共有します。

LoadingWheel

LoadingWheelでは唯一アニメーションのスクリーンショットが撮影されています。実装は以下になります。
https://github.com/android/nowinandroid/blob/3ff5d48f3739c2341bfb288779e35ff444015783/core/designsystem/src/test/kotlin/com/google/samples/apps/nowinandroid/core/designsystem/LoadingWheelScreenshotTests.kt#L65-L82

Compose テストはデフォルトで UI と同期される仕様があります。[2]
つまり UI がアイドル状態(アニメーションが完了している状態)となるまでスクリーンショットのキャプチャを行うことはできません。
これを解決するために 67 行目でまず同期を解除しています。

composeTestRule.mainClock.autoAdvance = false

同期を解除したので、次は自分で時間を進める処理が必要となります。
これは 75 行目のadvanceTimeByで行われています。

listOf(20L, 115L, 724L, 1000L).forEach { deltaTime ->
  composeTestRule.mainClock.advanceTimeBy(deltaTime)
...

これらの処理によってアニメーションが進行している間の任意のフレームずつcaptureRoboImageを使ってスクリーンショットの撮影を行うことが可能となっているわけです。

now in android で実践されている Roborazzi でアニメーションのスクリーンショットを撮影するテクニックは Android Test Night#9[3]@sumio さんが発表されていた内容[4]の一つでもあり、コードを読んでいた際にテンションが上がりました。

app

NiaAppScreenSizesScreenshotTests.kt にて使用されています。
テーマは関係なく、ひたすら色んな幅や高さのスクリーンショットを撮っています。
ここでcaptureMultiDeviceを使わなかった理由としては3つのデバイスのスペックだけでなくいろいろな高さや幅のスクリーンショットを撮影するためだと考えられます。

feature/foryou

ForYouScreenScreenshotTests.kt にて使用されています。
前述した captureForDevicecaptureMultiDeviceによってデバイスごとに丁寧にスクリーンショットが撮影されています。

おわりに

now in android は最新知識の宝庫なので読んでいると楽しいし知識も仕入れられるしで一石二鳥ですね!
効率良くスクリーンショットテストを撮影するために適切な拡張関数を作成するのは大事だと感じました。

現状、/featureではforyouモジュールしか Roborazzi によるスクリーンショットテストが実装されていないので今後も増えることが予想されます。なので随時記事をアップデートしていけたらなと思っています。
ヘルパー関数のあたりは詳しい実装を説明していないので気になった方はぜひリポジトリのソースを読みに行ってみてください。

記事内で解釈違いの部分やここも注目するべきなどの箇所があればお手柔らかに教えていただけると幸いです。

お読みいただきありがとうございました。

脚注

脚注
  1. 該当 PR ↩︎

  2. https://developer.android.com/jetpack/compose/testing?hl=ja#sync ↩︎

  3. https://testnight.connpass.com/event/305270/ ↩︎

  4. https://speakerdeck.com/sumio/a-collection-of-useful-tips-for-taking-screenshots-in-roborazzi?slide=31 ↩︎

Discussion