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
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
Navigating the moral maze — ethical principles for Al-driven product design
skipperchong
2
520
How Software Deployment tools have changed in the past 20 years
geshan
1
34k
How to make the Groovebox
asonas
2
2.4k
Building Flexible Design Systems
yeseniaperezcruz
330
41k
Leveraging LLMs for student feedback in introductory data science courses - posit::conf(2025)
minecr
1
380
The Art of Programming - Codeland 2020
erikaheidi
57
14k
The AI Revolution Will Not Be Monopolized: How open-source beats economies of scale, even for LLMs
inesmontani
PRO
3
3.7k
Done Done
chrislema
186
16k
Facilitating Awesome Meetings
lara
57
7.1k
Taking LLMs out of the black box: A practical guide to human-in-the-loop distillation
inesmontani
PRO
3
2.4k
Bioeconomy Workshop: Dr. Julius Ecuru, Opportunities for a Bioeconomy in West Africa
akademiya2063
PRO
1
350
Exploring anti-patterns in Rails
aemeredith
3
500
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を使っているかを考えよう ・コードには理由がある(はず) ・やってないことに対して、すぐにできるでしょみたいに⾼を括らないようにしよう ・⾃分がやることにも他⼈がやることに対しても
ご清聴ありがとうございました!