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
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
gotlin
May 09, 2024
370
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
45
Applicationクラスのライフサイクルに気をつけよう
goutarouh
0
87
Conference-app-2024の良さげな実装を勝手にいくつか紹介する
goutarouh
0
93
Drag & Drop in LazyColumn
goutarouh
0
960
Featured
See All Featured
AI Search: Where Are We & What Can We Do About It?
aleyda
0
7.9k
Building a Modern Day E-commerce SEO Strategy
aleyda
45
9.2k
Odyssey Design
rkendrick25
PRO
2
800
From π to Pie charts
rasagy
0
360
The innovator’s Mindset - Leading Through an Era of Exponential Change - McGill University 2025
jdejongh
PRO
1
330
Documentation Writing (for coders)
carmenintech
77
5.5k
CSS Pre-Processors: Stylus, Less & Sass
bermonpainter
360
30k
Marketing to machines
jonoalderson
1
5.8k
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
31
2.9k
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
133
19k
Visual Storytelling: How to be a Superhuman Communicator
reverentgeek
2
660
Heart Work Chapter 1 - Part 1
lfama
PRO
9
36k
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を使っているかを考えよう ・コードには理由がある(はず) ・やってないことに対して、すぐにできるでしょみたいに⾼を括らないようにしよう ・⾃分がやることにも他⼈がやることに対しても
ご清聴ありがとうございました!