Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
VRTをプロダクトに導入するまでのお話
Search
gotlin
May 09, 2024
380
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
VRTをプロダクトに導入するまでのお話
gotlin
May 09, 2024
More Decks by gotlin
See All by gotlin
KotlinConf2025現地参加 と Compose HotReload導入記
goutarouh
0
47
Applicationクラスのライフサイクルに気をつけよう
goutarouh
0
94
Conference-app-2024の良さげな実装を勝手にいくつか紹介する
goutarouh
0
98
Drag & Drop in LazyColumn
goutarouh
0
970
Featured
See All Featured
A Soul's Torment
seathinner
8
3.9k
brightonSEO & MeasureFest 2025 - Winning Strategies for Black Friday CRO & PPC - Christian Goodrich
cargoodrich
3
890
The Psychology of Web Performance [Beyond Tellerrand 2023]
tammyeverts
49
3.6k
Everyday Curiosity
cassininazir
0
400
Why You Should Never Use an ORM
jnunemaker
PRO
61
10k
ラッコキーワード サービス紹介資料
rakko
5
5.7M
Thoughts on Productivity
jonyablonski
76
5.5k
Beyond borders and beyond the search box: How to win the global "messy middle" with AI-driven SEO
davidcarrasco
3
300
The Hidden Cost of Media on the Web [PixelPalooza 2025]
tammyeverts
2
570
Effective software design: The role of men in debugging patriarchy in IT @ Voxxed Days AMS
baasie
1
600
The untapped power of vector embeddings
frankvandijk
2
2k
How Software Deployment tools have changed in the past 20 years
geshan
3
35k
Transcript
@gotlinan 2024/05/07 (⽕) DroidKaigi.collect { #8@Tokyo } VRTをプロダクトに 導⼊するまでのお話
所属: KINTOテクノロジーズ株式会社(通称KTC) モバイル開発グループ 開発: my route X(twitter): @gotlinan 趣味: バイク
my routeのVRT導⼊までの歴史 2024/4末~ 2023/11 2024/1 2023/12 2024/2 チーム内で VRT導⼊しちゃう〜? の声が出始める
Roborazziを 個⼈プロジェクト で導⼊ my routeでバグ発⽣ VRTがあれば 防げたかも。。。 my routeに 試験的に導⼊ とあるモジュールで実験 本格的実装 & 運⽤開始
Roborazzi導⼊に⾃信満々 2024/4末~ 2023/11 2024/1 2023/12 2024/2 チーム内で VRT導⼊しちゃう〜? の声が出始める Roborazziを
個⼈プロジェクト に導⼊ my routeでバグ発⽣ VRTがあれば 防げたかも。。。 my routeに 試験的に導⼊ とあるモジュールで実験 本格的実装 & 運⽤開始
Compose で動作確認 @RunWith(AndroidJUnit4::class) @GraphicsMode(GraphicsMode.Mode.NATIVE) class TestClass { @get:Rule val composeTestRule
= createComposeRule() @Test fun captureTestScreen() { composeTestRule.setContent { TestScreen(state = TEST_DATA) } composeTestRule.onRoot().captureRoboImage() } }
my routeの現在の構成 Activity Fragment A Fragment B xml (DataBinding) Compose
Compose xml (DataBinding)
Fragment × DataBinding × Hilt でVRTを⾏う必要がある
Fragment × DataBinding × Hilt で動作確認 @RunWith(AndroidJUnit4::class) @GraphicsMode(GraphicsMode.Mode.NATIVE) class TestClass
{ @Test fun captureTestFragment() { launchFragmentInContainer<TestFragment>() onView(withId(R.id.testFragment)).captureRoboImage() } }
Fragment × DataBinding × Hilt で動作確認 // https://issuetracker.google.com/issues/126775542 kaptTest("androidx.databinding:databinding-compiler:$version")
Fragment × DataBinding × Hilt で動作確認
Fragment × DataBinding × Hilt で動作確認 @AndroidEntryPoint class HiltTestActivity :
AppCompatActivity() https://github.com/android/architecture-samples/blob/dev- hilt/app/src/androidTest/java/com/example/android/architecture/blueprints/todoapp/HiltExt.kt
Fragment × DataBinding × Hilt で動作確認 inline fun <reified T
: Fragment> launchFragmentInHiltContainer( fragmentArgs: Bundle? = null, crossinline action: Fragment.() -> Unit = {}, ) { val startActivityIntent = Intent.makeMainActivity(ComponentName( ApplicationProvider.getApplicationContext(), HiltTestActivity::class.java, )) ActivityScenario.launch<HiltTestActivity>(startActivityIntent).onActivity { val fragment = it.supportFragmentManager.fragmentFactory.instantiate( Preconditions.checkNotNull(T::class.java.classLoader), T::class.java.name, ) fragment.arguments = fragmentArgs it.supportFragmentManager.beginTransaction().apply { add(android.R.id.content, fragment, "") }. commitNow() fragment.action() } } https://github.com/android/architecture-samples/blob/dev- hilt/app/src/androidTest/java/com/example/android/architecture/blueprints/todoapp/HiltExt.kt
@RunWith(AndroidJUnit4::class) @Config(application = HiltTestApplication::class) @HiltAndroidTest @GraphicsMode(GraphicsMode.Mode.NATIVE) class TestFragmentScreenShot { @get:Rule
var hiltRule = HiltAndroidRule(this) @Inject lateinit var xxxApi: XXXApi @Before fun setup() { hiltRule.inject() } @Test fun captureFragmentImage() { launchFragmentInHiltContainer<TestFragment> { onView(withId(R.id.testFragment)).captureRoboImage() } } } Fragment × DataBinding × Hilt で動作確認
@RunWith(AndroidJUnit4::class) @Config(application = HiltTestApplication::class) @HiltAndroidTest @GraphicsMode(GraphicsMode.Mode.NATIVE) class TestFragmentScreenShot { @get:Rule
var hiltRule = HiltAndroidRule(this) @Inject lateinit var xxxApi: XXXApi @Before fun setup() { hiltRule.inject() } @Test fun captureFragmentImage() { launchFragmentInHiltContainer<TestFragment> { onView(withId(R.id.testFragment)).captureRoboImage() } } } Fragment × DataBinding × Hilt で動作確認
@RunWith(AndroidJUnit4::class) @Config(application = HiltTestApplication::class) @HiltAndroidTest @GraphicsMode(GraphicsMode.Mode.NATIVE) class TestFragmentScreenShot { @get:Rule
var hiltRule = HiltAndroidRule(this) @Inject lateinit var xxxApi: XXXApi @Before fun setup() { hiltRule.inject() } @Test fun captureFragmentImage() { launchFragmentInHiltContainer<TestFragment> { onView(withId(R.id.testFragment)).captureRoboImage() } } } Fragment × DataBinding × Hilt で動作確認
⾊々な条件VRTできた! あとはプロジェクトに本格的に導⼊するだけ! ⼀⽇もあれば余裕だ!
…
テストが全然通らないぞ…? というかテストが終わらないぞ…?
[DefaultFileLockManager] Waiting to acquire shared lock on daemon addresse [DefaultFileLockManager]
Lock acquired on daemon addresses registry. [DefaultFileLockManager] Releasing lock on daemon addresses registry. java.lang.NullPointerException thrown from thread "FlipperConnectionThread" [DefaultFileLockManager] Waiting to acquire shared lock on daemon addresse [DefaultFileLockManager] Lock acquired on daemon addresses registry. [DefaultFileLockManager] Releasing lock on daemon addresses registry. [DefaultFileLockManager] Waiting to acquire shared lock on daemon addresse [DefaultFileLockManager] Lock acquired on daemon addresses registry. [DefaultFileLockManager] Releasing lock on daemon addresses registry. [DefaultFileLockManager] Waiting to acquire shared lock on daemon addresse [DefaultFileLockManager] Lock acquired on daemon addresses registry. [DefaultFileLockManager] Releasing lock on daemon addresses registry. [DefaultFileLockManager] Waiting to acquire shared lock on daemon addresse [DefaultFileLockManager] Lock acquired on daemon addresses registry. [DefaultFileLockManager] Releasing lock on daemon addresses registry. 以下永遠に続く……… 発⽣していたエラー
[DefaultFileLockManager] Waiting to acquire shared lock on daemon addresse [DefaultFileLockManager]
Lock acquired on daemon addresses registry. [DefaultFileLockManager] Releasing lock on daemon addresses registry. java.lang.NullPointerException thrown from thread "FlipperConnectionThread" [DefaultFileLockManager] Waiting to acquire shared lock on daemon addresse [DefaultFileLockManager] Lock acquired on daemon addresses registry. [DefaultFileLockManager] Releasing lock on daemon addresses registry. [DefaultFileLockManager] Waiting to acquire shared lock on daemon addresse [DefaultFileLockManager] Lock acquired on daemon addresses registry. [DefaultFileLockManager] Releasing lock on daemon addresses registry. [DefaultFileLockManager] Waiting to acquire shared lock on daemon addresse [DefaultFileLockManager] Lock acquired on daemon addresses registry. [DefaultFileLockManager] Releasing lock on daemon addresses registry. [DefaultFileLockManager] Waiting to acquire shared lock on daemon addresse [DefaultFileLockManager] Lock acquired on daemon addresses registry. [DefaultFileLockManager] Releasing lock on daemon addresses registry. 以下永遠に続く……… 発⽣していたエラー デッドロック的な…?
調べても全然解決できない🥺 きっとPCのスペックが⾜りないんだー! org.gradle.jvmargs=-Xmx4g gradle デーモン 再起動など ヒープ サイズ 拡⼤
よく⾒たら…
[DefaultFileLockManager] Waiting to acquire shared lock on daemon addresse [DefaultFileLockManager]
Lock acquired on daemon addresses registry. [DefaultFileLockManager] Releasing lock on daemon addresses registry. java.lang.NullPointerException thrown from thread "FlipperConnectionThread" [DefaultFileLockManager] Waiting to acquire shared lock on daemon addresse [DefaultFileLockManager] Lock acquired on daemon addresses registry. [DefaultFileLockManager] Releasing lock on daemon addresses registry. [DefaultFileLockManager] Waiting to acquire shared lock on daemon addresse [DefaultFileLockManager] Lock acquired on daemon addresses registry. [DefaultFileLockManager] Releasing lock on daemon addresses registry. [DefaultFileLockManager] Waiting to acquire shared lock on daemon addresse [DefaultFileLockManager] Lock acquired on daemon addresses registry. [DefaultFileLockManager] Releasing lock on daemon addresses registry. [DefaultFileLockManager] Waiting to acquire shared lock on daemon addresse [DefaultFileLockManager] Lock acquired on daemon addresses registry. [DefaultFileLockManager] Releasing lock on daemon addresses registry. 以下永遠に続く……… 発⽣していたエラー (--debug オプションが必要) Flipper…?
・Flipperとはmy routeで使⽤しているデバッグツール ・Applicationクラスで設定 ・Applicationクラスを、Manifestファイルで指定 class MyrouteApplication : Application() { override
fun onCreate() { Flipper.initialize(this) ... } } Flipperについて <application android:name=".MyrouteApplication" /> </application>
Composeでテストを⾏うとき、起動するActivityの宣⾔があるManifestをマージする // build.gradle debugImplementation("androidx.compose.ui:ui-test-manifest:$version") <!-- app/build/merged-manifest/ --> <activity android:name="androidx.activity.ComponentActivity" android:exported="true"
/> 専⽤のActivityをManifestにマージする
// モジュールのbuild.gradle.kts android { testOptions { unitTests { isIncludeAndroidResources =
true } } } Roborazzi使うときに必要な設定 > Enables unit tests to use Android resources, assets, and manifests. https://developer.android.com/reference/tools/gradle-api/8.3/com/android/build/api/dsl/UnitTestOptions#isIncludeAndroidResou
@RunWith(AndroidJUnit4::class) @Config(application = Application::class) @GraphicsMode(GraphicsMode.Mode.NATIVE) class TestClass { } 対応⽅法
約半年後、 ようやく導⼊できました…!
教訓 ・エラー⽂はちゃんと読もう ・必要に応じて、./gradlew XXX --debug などを活⽤しよう ・何でdebugImplementationを使っているかを考えよう ・コードには理由がある(はず) ・やってないことに対して、すぐにできるでしょみたいに⾼を括らないようにしよう ・⾃分がやることにも他⼈がやることに対しても
ご清聴ありがとうございました!