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
CIでAndroidUIテストの様子を録画してみた
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
mkeeda
May 17, 2022
Programming
780
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
CIでAndroidUIテストの様子を録画してみた
Mobile勉強会 Wantedly × チームラボ #5
https://wantedly.connpass.com/event/244011/
mkeeda
May 17, 2022
More Decks by mkeeda
See All by mkeeda
Google I/O 2026 個人的に気になりトピック
mkeeda
0
19
アジャイル & スクラム入門
mkeeda
0
190
そのAPI、誰のため? Androidライブラリ設計における利用者目線の実践テクニック
mkeeda
2
5.5k
Android StudioのAIコーディングツール、 ぶっちゃけどうなん???
mkeeda
0
610
DataStoreをテストする
mkeeda
0
590
時計仕掛けのCompose
mkeeda
1
560
What's new in Firebase for building gen AI features気になったところ
mkeeda
0
960
手動DIの教訓
mkeeda
0
300
WebViewと向き合う
mkeeda
2
1.7k
Other Decks in Programming
See All in Programming
吝嗇家のためのAI活用 / AI development for miser - ChatGPT + Issue Driven Development
tooppoo
0
180
SREの積み重ねがAI駆動開発のガードレールになった ― 7つの実践/SRE Guardrails The 7
tomoyakitaura
8
4k
Hunting Vulnerabilities in Symfony with LLMs
vinceamstoutz
0
580
地域 SRE コミュニティ最前線 - ホンマでっかSRE勉強会
tk3fftk
0
220
信頼性について考えてみる(SRE NEXT 2026 miniLT)
hayama17
0
160
PHPだって関数型したい 〜できること、できないこと〜 / fp-in-php
jsoizo
0
190
どこまでゆるくて許されるのか
tk3fftk
0
470
Performance Engineering for Everyone
elenatanasoiu
0
270
AI時代、エンジニアはどう育つのか -未経験エンジニアの成長を間近で見て考えたこと-
thasu0123
0
110
ローカルLLMでどこまでコードが書けるか -縮小版 / How much code can be written on a local LLM Shortened
kishida
2
190
act2-costs.pdf
sumedhbala
0
110
エンジニアにデザインハーネスを 〜デザインプロセスを規定するためのハーネス〜 / Design harness from an engineer's perspective
rkaga
2
1.4k
Featured
See All Featured
Tips & Tricks on How to Get Your First Job In Tech
honzajavorek
1
560
Primal Persuasion: How to Engage the Brain for Learning That Lasts
tmiket
0
390
HDC tutorial
michielstock
2
740
Redefining SEO in the New Era of Traffic Generation
szymonslowik
1
360
How STYLIGHT went responsive
nonsquared
100
6.2k
WCS-LA-2024
lcolladotor
0
680
Responsive Adventures: Dirty Tricks From The Dark Corners of Front-End
smashingmag
254
22k
Beyond borders and beyond the search box: How to win the global "messy middle" with AI-driven SEO
davidcarrasco
3
180
Discover your Explorer Soul
emna__ayadi
2
1.2k
How to Ace a Technical Interview
jacobian
281
24k
Building the Perfect Custom Keyboard
takai
2
810
Making the Leap to Tech Lead
cromwellryan
135
10k
Transcript
CIでAndroidUIテストの様⼦を 録画してみた .PCJMFษڧձ8BOUFEMZºνʔϜϥϘ NLFFEB
About me • mkeeda (向井⽥ ⼀平) • Twitter: @mr_mkeeda •
Github: @mkeeda • Android Engineer at Cybozu, Inc 2
UIテストあるある • 不安定🤮 • CIでだけUIテストが落ちる🤮 • エラーがよくわからない🤮 • エラーが毎回違う🤮 3
UIテストの様⼦を録画してみた • CIのテスト実⾏時は Androidエミュレータの画⾯が⾒れない • UIテストが落ちるときの画⾯の状態を知りたい • Firebase test
labは使ってない • テスト失敗時にGithub Actionsの アーティファクトに録画データを残す 4
Androidデバイス画⾯収録の基本 • 録画開始 • adb shell screenrecord <ファイルパス> • ※ファイルパスはAndroidデバイスのパス
• 録画停⽌ • Ctrl + C (mac は Command + C) • 録画ファイル取得 • adb pull <録画ファイルのパス> <ローカルデバイスの保存先パス> 5
テストケースごとに録画してみる • ScreenRecordRule を作る • “record_<テストメソッド名>.mp4” というファイル名で保存する 6 @RunWith(AndroidJUnit4::class) class
SampleUiTest { @get:Rule var activityRule: ActivityScenarioRule<LoginActivity> = ActivityScenarioRule(LoginActivity::class.java) @get:Rule var screenRecordRule = ScreenRecordRule() @Test fun test() { // run test } }
テストコードから adb コマンドを実⾏ • UiAutomation.executeShellCommand(String command) を使う • ローカルマシンで adb
shell <command> をするのと同等 7 val uiAutomation = InstrumentationRegistry.getInstrumentation().uiAutomation // ը։࢝ uiAutomation.executeShellCommand("screenrecord /sdcard/record.mp4") // ըऴྃ (Ctrl + C) ϓϩηεID͕ඞཁ uiAutomation.executeShellCommand("kill -SIGINT $screenRecordProcessId")
screenrecord のプロセスを得る 8 fun executeCommand(cmd: String): String { val parcelFileDescriptor
= uiAutomation.executeShellCommand(cmd) return ParcelFileDescriptor.AutoCloseInputStream(parcelFileDescriptor).use { inputStream -> inputStream.readBytes().toString(Charset.defaultCharset()) } } fun findProcessIds(processName: String): List<Int> { return executeCommand(cmd = "pidof $processName") .trim() .split(Regex("\\s+")) .filter { it.isNotEmpty() } .map { it.toInt() } } val screenRecordProcessIds = findProcessIds(processName = "screenrecord")
ScreenRecordRule 9 class ScreenRecordRule : TestWatcher() { private val shell
= Shell() private var screenRecordProcessIds: List<Int> = emptyList() override fun starting(description: Description) { shell.executeCommand(cmd = "screenrecord /sdcard/record_${description.methodName}.mp4", awaitOutput = false) screenRecordProcessIds = shell.findProcessIds(processName = "screenrecord") } override fun finished(description: Description) { // গ͠Ԇ͔ͤͯ͞Βऴྃͤ͞ͳ͍ͱ࠷ޙ·ͰըͰ͖ͳ͍ͱ͖͕͋ͬͨͷͰํͳ͘ Thread.sleep(5000) // ͯ͢ͷscreenrecordϓϩηεΛࢭΊΔ // 1σόΠεͰ࣮ߦ͍ͯ͠ΕଞͷςετέʔεͷըΛࢭΊͯ͠·͏Մೳੑ͍ͣ screenRecordProcessIds.forEach { pid -> shell.executeCommand(cmd = "kill -SIGINT $pid", awaitOutput = false) } } }
Github Actionsでの録画データの回収 • テストが失敗したときだけ録画をCIのアーティファクトとして保存する 10 - name: Run android tests
uses: reactivecircus/android-emulator-runner@v2 with: api-level: 31 arch: x86_64 disable-animations: true script: | ./gradlew connectedDebugAndroidTest || (mkdir screen_record; adb shell 'ls sdcard/record_*.mp4' | tr -d '\r' | xargs -I% adb pull % ./screen_record && exit 1) - name: Save screen record if: failure() uses: actions/upload-artifact@v2 with: name: screen-records path: ./screen_record
• adbコマンドを使えばAndroidTestの実⾏の様⼦を 録画できる • 実⾏時の様⼦を知って テスト失敗時の原因追求ができる • 乱⽤するとテスト時間の増⼤に繋がりそう
• ScreenRecordRuleのソースコード https://gist.github.com/mkeeda/30b8cfdcec53859a2cd39cac36d7fc9e 11 まとめ To Be Continued
参考 • Android Debug Bridge (adb) | Android Developers
https://developer.android.com/studio/command-line/adb • UiAutomation | Android Developers https://developer.android.com/reference/android/app/ UiAutomation#executeShellCommand(java.lang.String) • androidx.benchmark.Shell https://cs.android.com/androidx/platform/frameworks/support/+/ androidx-main:benchmark/benchmark-common/src/main/java/androidx/ benchmark/Shell.kt 12