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
260
Roborazziを最大限に活用する(導入編)
12/1のDroidKaigi.collect { #7@TOkyo } で登壇した資料です
Swimmy
December 01, 2023
Tweet
Share
More Decks by Swimmy
See All by Swimmy
違いがワカルKotlinプログラマーへの道
reoandroider
0
120
違いのワカル Kotlinプログラマーへの道
reoandroider
0
190
[Jetpack Compose] 原理から見るSkippable対応
reoandroider
1
290
Androdアプリ開発におけるネストスクロール問題と向き合うの説明用途
reoandroider
0
2.3k
Androdアプリ開発におけるネストスクロール問題と向き合うの説明用途
reoandroider
0
2.2k
Androdアプリ開発におけるネストスクロール問題と向き合うの説明用途~NestedScrollInteropConnectionは何してるの?編~
reoandroider
0
2.1k
Master of NestedScroll
reoandroider
0
12k
Jetpack_Composeで_半円のプログレスバーを作った話
reoandroider
0
360
Compose「急いで」キャッチアップする
reoandroider
0
19
Featured
See All Featured
No one is an island. Learnings from fostering a developers community.
thoeni
19
3k
Docker and Python
trallard
42
3.1k
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
32
2.7k
The Invisible Side of Design
smashingmag
298
50k
The Art of Programming - Codeland 2020
erikaheidi
53
13k
Raft: Consensus for Rubyists
vanstee
137
6.7k
The Straight Up "How To Draw Better" Workshop
denniskardys
232
140k
Creating an realtime collaboration tool: Agile Flush - .NET Oxford
marcduiker
26
1.9k
XXLCSS - How to scale CSS and keep your sanity
sugarenia
247
1.3M
Building Your Own Lightsaber
phodgson
103
6.1k
Become a Pro
speakerdeck
PRO
26
5k
Practical Tips for Bootstrapping Information Extraction Pipelines
honnibal
PRO
10
810
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