Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Roborazziを最大限に活用する(導入編)
Search
Swimmy
December 01, 2023
0
320
Roborazziを最大限に活用する(導入編)
12/1のDroidKaigi.collect { #7@TOkyo } で登壇した資料です
Swimmy
December 01, 2023
Tweet
Share
More Decks by Swimmy
See All by Swimmy
Android16 Migration Stories ~Building a Pattern for Android OS upgrades~
reoandroider
0
110
違いがワカルKotlinプログラマーへの道
reoandroider
0
140
違いのワカル Kotlinプログラマーへの道
reoandroider
0
230
[Jetpack Compose] 原理から見るSkippable対応
reoandroider
1
340
Androdアプリ開発におけるネストスクロール問題と向き合うの説明用途
reoandroider
0
3k
Androdアプリ開発におけるネストスクロール問題と向き合うの説明用途
reoandroider
0
2.9k
Androdアプリ開発におけるネストスクロール問題と向き合うの説明用途~NestedScrollInteropConnectionは何してるの?編~
reoandroider
0
2.6k
Master of NestedScroll
reoandroider
0
14k
Jetpack_Composeで_半円のプログレスバーを作った話
reoandroider
0
430
Featured
See All Featured
Into the Great Unknown - MozCon
thekraken
40
2.1k
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
140
34k
KATA
mclloyd
32
15k
Code Review Best Practice
trishagee
72
19k
Keith and Marios Guide to Fast Websites
keithpitt
411
23k
ピンチをチャンスに:未来をつくるプロダクトロードマップ #pmconf2020
aki_iinuma
127
53k
We Have a Design System, Now What?
morganepeng
53
7.8k
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
31
2.5k
Music & Morning Musume
bryan
46
6.8k
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
132
19k
YesSQL, Process and Tooling at Scale
rocio
173
14k
Connecting the Dots Between Site Speed, User Experience & Your Business [WebExpo 2025]
tammyeverts
9
590
Transcript
Harada Reo @ すいみー DroidKaigi @Tokyo .collect {} Roborazziを最大限に活用する (導入編)
すいみー CyberAgent Inc. Ameba どすこい塾 DroidKaigi Staff RunningReo(X) 自己紹介 /
Introduction
このLTのゴール 聞いてくれた人が Roborazziを スムーズに導入できる状態
Roborazzi Roborazziとは? takahiromさんによる 静的なスクリーンショットテストライブラリ https://github.com/takahirom/roborazzi
目次 / Index プロダクトが抱えている課題 2 3 今後の展望 1 Roborazzi導入手順
プロダクトが抱えている課題 1
紹介 Ameba ブログや話題の芸能ニュースを毎日お届け! https://play.google.com/store/apps/details?id=jp.ameba&hl=ja&gl=US
紹介 リリースから10年以上運用している
紹介 Amebaでは Roborazziを 導入中・・・
課題点 アプリの画面数が多く QCさんによる デグレ確認のテスト項目が 膨大な量になっている
解決アプローチ Roborazziを用いることで 目視確認を自動化して 品質担保を目指す
Roborazzi導入手順 2
前提の話 ・Hilt対応していると楽 ・Jetpack ComposeもAndroidViewも 相互運用も対応しているよ
前提の話 ・Hilt対応していると楽 ・Jetpack ComposeもAndroidViewも 相互運用も対応しているよ
前提の話 ・Hilt対応していると楽 ・Jetpack ComposeもAndroidViewも 相互運用も対応しているよ Activityをベースにテストする時にテスト用のApplicationクラスを Robolectricに登録するなど冗長的な作業が発生する
前提の話 ・Hilt対応していると楽 ・Jetpack ComposeもAndroidViewも 相互運用も対応しているよ
前提の話 ・Hilt対応していると楽 ・Jetpack ComposeもAndroidViewも 相互運用も対応しているよ ComposeRuleが内部でActivityScenarioを用いているため // 内部実装 inline fun
<reified A : ComponentActivity> createAndroidComposeRule(): AndroidComposeTestRule<ActivityScenarioRule<A>, A> { return createAndroidComposeRule(A::class.java) }
依存関係の追加 // root build.gradle buildScript { dependencies { classPath =
"io.github.takahirom.roborazzi:roborazzi-gradle-plugin: [version]" } }
依存関係の追加 // module build.gradle apply plugin: "io.github.takahirom.roborazzi" android { testOptions
{ unitTests { includeAndroidResources = true } } } dependencies { testImplementation "androidx.test.ext:junit-ktx:[version]" testImplementation "org.robolectric:robolectric:[4.10-alpha以上]" testImplementation "io.github.takahirom.roborazzi:roborazzi:[version]" testImplementation "androidx.compose.ui:ui-test-junit4:[version]" }
依存関係の追加 // module build.gradle apply plugin: "io.github.takahirom.roborazzi" android { testOptions
{ unitTests { includeAndroidResources = true } } } dependencies { testImplementation "androidx.test.ext:junit-ktx:[version]" testImplementation "org.robolectric:robolectric:[4.10-alpha以上]" testImplementation "io.github.takahirom.roborazzi:roborazzi:[version]" testImplementation "androidx.compose.ui:ui-test-junit4:[version]" }
依存関係の追加 // module build.gradle apply plugin: "io.github.takahirom.roborazzi" android { testOptions
{ unitTests { includeAndroidResources = true } } } dependencies { testImplementation "androidx.test.ext:junit-ktx:[version]" testImplementation "org.robolectric:robolectric:[4.10-alpha以上]" testImplementation "io.github.takahirom.roborazzi:roborazzi:[version]" testImplementation "androidx.compose.ui:ui-test-junit4:[version]" }
依存関係の追加 // module build.gradle apply plugin: "io.github.takahirom.roborazzi" android { testOptions
{ unitTests { includeAndroidResources = true } } } dependencies { testImplementation "androidx.test.ext:junit-ktx:[version]" testImplementation "org.robolectric:robolectric:[4.10-alpha以上]" testImplementation "io.github.takahirom.roborazzi:roborazzi:[version]" testImplementation "androidx.compose.ui:ui-test-junit4:[version]" }
依存関係の追加 // module build.gradle apply plugin: "io.github.takahirom.roborazzi" android { testOptions
{ unitTests { includeAndroidResources = true } } } dependencies { testImplementation "androidx.test.ext:junit-ktx:[version]" testImplementation "org.robolectric:robolectric:[4.10-alpha以上]" testImplementation "io.github.takahirom.roborazzi:roborazzi:[version]" testImplementation "androidx.compose.ui:ui-test-junit4:[version]" }
依存関係の追加 // module build.gradle apply plugin: "io.github.takahirom.roborazzi" android { testOptions
{ unitTests { includeAndroidResources = true } } } dependencies { testImplementation "androidx.test.ext:junit-ktx:[version]" testImplementation "org.robolectric:robolectric:[4.10-alpha以上]" testImplementation "io.github.takahirom.roborazzi:roborazzi:[version]" testImplementation "androidx.compose.ui:ui-test-junit4:[version]" }
依存関係の追加 // module build.gradle apply plugin: "io.github.takahirom.roborazzi" android { testOptions
{ unitTests { includeAndroidResources = true } } } dependencies { testImplementation "androidx.test.ext:junit-ktx:[version]" testImplementation "org.robolectric:robolectric:[4.10-alpha以上]" testImplementation "io.github.takahirom.roborazzi:roborazzi:[version]" testImplementation "androidx.compose.ui:ui-test-junit4:[version]" }
テストクラス作成 @RunWith(AndroidJUnit4::class) @GraphicsMode(GraphicsMode.Mode.NATIVE) class BookmarkScreenShotTest { ...
テストクラス作成 @RunWith(AndroidJUnit4::class) @GraphicsMode(GraphicsMode.Mode.NATIVE) class BookmarkScreenShotTest { ...Robolectric4.10-alphaから使える実装 ネイティブのグラフィックをサポート
テストクラス作成 ... class BookmarkScreenShotTest { @get:Rule(order = 1) val addActivityToRobolectricRule
= object : TestWatcher() { override fun starting(description: Description?) { super.starting(description) val appContext: Application = ApplicationProvider.getApplicationContext() val activityInfo = ActivityInfo().apply { name = ComponentActivity::class.java.name packageName = appContext.packageName } shadowOf(appContext.packageManager).addOrUpdateActivity(activityInfo) } }
テストクラス作成 ... class BookmarkScreenShotTest { @get:Rule(order = 1) val addActivityToRobolectricRule
= object : TestWatcher() { override fun starting(description: Description?) { super.starting(description) val appContext: Application = ApplicationProvider.getApplicationContext() val activityInfo = ActivityInfo().apply { name = ComponentActivity::class.java.name packageName = appContext.packageName } shadowOf(appContext.packageManager).addOrUpdateActivity(activityInfo) } } RobolectricへのActivityの登録を行う
テストクラス作成 ... class BookmarkScreenShotTest { @get:Rule(order = 1) val addActivityToRobolectricRule
= object : TestWatcher() { override fun starting(description: Description?) { super.starting(description) val appContext: Application = ApplicationProvider.getApplicationContext() val activityInfo = ActivityInfo().apply { name = ComponentActivity::class.java.name packageName = appContext.packageName } shadowOf(appContext.packageManager).addOrUpdateActivity(activityInfo) } } 登録できてないとエラーが発生する java.lang.RuntimeException: Unable to resolve activity for Intent...
テストクラス作成 ... class BookmarkScreenShotTest { ... @get:Rule(order = 2) val
composeRule = createComposeRule() @Test @Config(sdk = [33], qualifiers = RobolectricDeviceQualifiers.Pixel7) fun captureSampleScreen() { composeRule.setContent { SampleTheme { SampleScreen(...) } } composeRule.onNode(isRoot()).captureRoboImage() }
テストクラス作成 ... class BookmarkScreenShotTest { ... @get:Rule(order = 2) val
composeRule = createComposeRule() @Test @Config(sdk = [33], qualifiers = RobolectricDeviceQualifiers.Pixel7) fun captureSampleScreen() { composeRule.setContent { SampleTheme { SampleScreen(...) } } composeRule.onNode(isRoot()).captureRoboImage() } createComopseRuleを呼び出す
テストクラス作成 ... class BookmarkScreenShotTest { ... @get:Rule(order = 2) val
composeRule = createComposeRule() @Test @Config(sdk = [33], qualifiers = RobolectricDeviceQualifiers.Pixel7) fun captureSampleScreen() { composeRule.setContent { SampleTheme { SampleScreen(...) } } composeRule.onNode(isRoot()).captureRoboImage() } スクショする端末のSDKと機種を指定
テストクラス作成 ... class BookmarkScreenShotTest { ... @get:Rule(order = 2) val
composeRule = createComposeRule() @Test @Config(sdk = [33], qualifiers = RobolectricDeviceQualifiers.Pixel7) fun captureSampleScreen() { composeRule.setContent { SampleTheme { SampleScreen(...) } } composeRule.onNode(isRoot()).captureRoboImage() } Composeを起動させる
テストクラス作成 ... class BookmarkScreenShotTest { ... @get:Rule(order = 2) val
composeRule = createComposeRule() @Test @Config(sdk = [33], qualifiers = RobolectricDeviceQualifiers.Pixel7) fun captureSampleScreen() { composeRule.setContent { SampleTheme { SampleScreen(...) } } composeRule.onNode(isRoot()).captureRoboImage() } captureRoboImageでスクショを撮る
テスト実行 ./gradlew recordRoborazziDebug 初期状態のスクショを撮る・比較におけるbefore ./gradlew compareRoborazziDebug 差分のスクショを撮る ./gradlew verifyRoborazziDebug 差分があるかどうかのテスト
./gradlew verifyAndRecordRoborazziDebug 差分があるかどうかとスクショを撮る
テスト実行 ./gradlew recordRoborazziDebug 初期状態のスクショを撮る・比較におけるbefore ./gradlew compareRoborazziDebug 差分のスクショを撮る ./gradlew verifyRoborazziDebug 差分があるかどうかのテスト
./gradlew verifyAndRecordRoborazziDebug 差分があるかどうかとスクショを撮る
./gradlew recordRoborazziDebug 初期状態のスクショを撮る・比較におけるbefore ./gradlew compareRoborazziDebug 差分のスクショを撮る ./gradlew verifyRoborazziDebug 差分があるかどうかのテスト ./gradlew
verifyAndRecordRoborazziDebug 差分があるかどうかとスクショを撮る テスト実行
./gradlew recordRoborazziDebug 初期状態のスクショを撮る・比較におけるbefore ./gradlew compareRoborazziDebug 差分のスクショを撮る ./gradlew verifyRoborazziDebug 差分があるかどうかのテスト ./gradlew
verifyAndRecordRoborazziDebug 差分があるかどうかとスクショを撮る テスト実行
./gradlew recordRoborazziDebug 初期状態のスクショを撮る・比較におけるbefore ./gradlew compareRoborazziDebug 差分のスクショを撮る ./gradlew verifyRoborazziDebug 差分があるかどうかのテスト ./gradlew
verifyAndRecordRoborazziDebug 差分があるかどうかとスクショを撮る テスト実行
./gradlew recordRoborazziDebug 初期状態のスクショを撮る・比較におけるbefore ./gradlew compareRoborazziDebug 差分のスクショを撮る ./gradlew verifyRoborazziDebug 差分があるかどうかのテスト ./gradlew
verifyAndRecordRoborazziDebug 差分があるかどうかとスクショを撮る テスト実行
./gradlew recordRoborazziDebug 初期状態のスクショを撮る・比較におけるbefore ./gradlew compareRoborazziDebug 差分のスクショを撮る ./gradlew verifyRoborazziDebug 差分があるかどうかのテスト ./gradlew
verifyAndRecordRoborazziDebug 差分があるかどうかとある場合にスクショを撮る テスト実行
今後の展望 3
このLTのゴール 聞いてくれた人が Roborazziを スムーズに導入できる状態
まとめ 躓いて何日かハマったこともあったが 一度スクショ撮れるとあとは楽
まとめ 導入始めたばかりなので まだ検証したいことはある ・ベンチマークの設定 ・CIの時間への影響 ・UIテストとの兼ね合い
まとめ 品質担保において活用できるが エンジニアだけが使う ツールで消費されるのは もったいない気がする
まとめ デザイナーとのコミュニケーションを 円滑にする手段として活用したい (カタログやデザインシステムの準拠など)
まとめ 現状スクショのdiff詳細は見れないので OSSやEspressoのdump出力を活用して 最大限活用する方法を見つけていきたい
Harada Reo @ すいみー Roborazziを最大限に活かす (運用編)
to be continued