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
mkeeda
May 17, 2022
Programming
1
690
CIでAndroidUIテストの様子を録画してみた
Mobile勉強会 Wantedly × チームラボ #5
https://wantedly.connpass.com/event/244011/
mkeeda
May 17, 2022
Tweet
Share
More Decks by mkeeda
See All by mkeeda
そのAPI、誰のため? Androidライブラリ設計における利用者目線の実践テクニック
mkeeda
2
2.8k
Android StudioのAIコーディングツール、 ぶっちゃけどうなん???
mkeeda
0
15
DataStoreをテストする
mkeeda
0
450
時計仕掛けのCompose
mkeeda
1
410
What's new in Firebase for building gen AI features気になったところ
mkeeda
0
750
手動DIの教訓
mkeeda
0
220
WebViewと向き合う
mkeeda
2
1.4k
お気に入りのAndroid Studio小技集
mkeeda
0
350
Scalable UI testing solutions かんたんまとめ
mkeeda
0
1.2k
Other Decks in Programming
See All in Programming
アルテニア コンサル/ITエンジニア向け 採用ピッチ資料
altenir
0
110
個人軟體時代
ethanhuang13
0
330
MCPでVibe Working。そして、結局はContext Eng(略)/ Working with Vibe on MCP And Context Eng
rkaga
5
2.3k
GitHubとGitLabとAWS CodePipelineでCI/CDを組み比べてみた
satoshi256kbyte
4
250
Swift Updates - Learn Languages 2025
koher
2
510
Deep Dive into Kotlin Flow
jmatsu
1
370
Namespace and Its Future
tagomoris
6
710
Ruby×iOSアプリ開発 ~共に歩んだエコシステムの物語~
temoki
0
350
プロポーザル駆動学習 / Proposal-Driven Learning
mackey0225
2
1.3k
プロパティベーステストによるUIテスト: LLMによるプロパティ定義生成でエッジケースを捉える
tetta_pdnt
0
4.3k
CJK and Unicode From a PHP Committer
youkidearitai
PRO
0
110
「手軽で便利」に潜む罠。 Popover API を WCAG 2.2の視点で安全に使うには
taitotnk
0
870
Featured
See All Featured
Speed Design
sergeychernyshev
32
1.1k
Put a Button on it: Removing Barriers to Going Fast.
kastner
60
4k
ReactJS: Keep Simple. Everything can be a component!
pedronauck
667
120k
How STYLIGHT went responsive
nonsquared
100
5.8k
CoffeeScript is Beautiful & I Never Want to Write Plain JavaScript Again
sstephenson
162
15k
Building Better People: How to give real-time feedback that sticks.
wjessup
368
19k
KATA
mclloyd
32
14k
Connecting the Dots Between Site Speed, User Experience & Your Business [WebExpo 2025]
tammyeverts
8
530
The Pragmatic Product Professional
lauravandoore
36
6.9k
Keith and Marios Guide to Fast Websites
keithpitt
411
22k
10 Git Anti Patterns You Should be Aware of
lemiorhan
PRO
656
61k
Visualization
eitanlees
148
16k
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