Upgrade to Pro — share decks privately, control downloads, hide ads and more …

CIでAndroidUIテストの様子を録画してみた

 CIでAndroidUIテストの様子を録画してみた

Mobile勉強会 Wantedly × チームラボ #5
https://wantedly.connpass.com/event/244011/

mkeeda

May 17, 2022
Tweet

More Decks by mkeeda

Other Decks in Programming

Transcript

  1. CIでAndroidUIテストの様⼦を
    録画してみた
    .PCJMFษڧձ8BOUFEMZºνʔϜϥϘ
    NLFFEB

    View full-size slide

  2. About me
    • mkeeda (向井⽥ ⼀平)
    • Twitter: @mr_mkeeda
    • Github: @mkeeda
    • Android Engineer at Cybozu, Inc
    2

    View full-size slide

  3. UIテストあるある
    • 不安定🤮
    • CIでだけUIテストが落ちる🤮
    • エラーがよくわからない🤮
    • エラーが毎回違う🤮
    3

    View full-size slide

  4. UIテストの様⼦を録画してみた
    • CIのテスト実⾏時は

    Androidエミュレータの画⾯が⾒れない
    • UIテストが落ちるときの画⾯の状態を知りたい
    • Firebase test labは使ってない
    • テスト失敗時にGithub Actionsの

    アーティファクトに録画データを残す
    4

    View full-size slide

  5. Androidデバイス画⾯収録の基本
    • 録画開始
    • adb shell screenrecord <ファイルパス>
    • ※ファイルパスはAndroidデバイスのパス
    • 録画停⽌
    • Ctrl + C (mac は Command + C)
    • 録画ファイル取得
    • adb pull <録画ファイルのパス> <ローカルデバイスの保存先パス>
    5

    View full-size slide

  6. テストケースごとに録画してみる
    • ScreenRecordRule を作る
    • “record_<テストメソッド名>.mp4” というファイル名で保存する
    6
    @RunWith(AndroidJUnit4::class)
    class SampleUiTest {
    @get:Rule
    var activityRule: ActivityScenarioRule =
    ActivityScenarioRule(LoginActivity::class.java)
    @get:Rule
    var screenRecordRule = ScreenRecordRule()
    @Test
    fun test() {
    // run test
    }
    }

    View full-size slide

  7. テストコードから adb コマンドを実⾏
    • UiAutomation.executeShellCommand(String command) を使う
    • ローカルマシンで adb shell をするのと同等
    7
    val uiAutomation = InstrumentationRegistry.getInstrumentation().uiAutomation
    // ࿥ը։࢝


    uiAutomation.executeShellCommand("screenrecord /sdcard/record.mp4")
    // ࿥ըऴྃ (Ctrl + C) ϓϩηεID͕ඞཁ
    uiAutomation.executeShellCommand("kill -SIGINT $screenRecordProcessId")

    View full-size slide

  8. 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 {
    return executeCommand(cmd = "pidof $processName")
    .trim()
    .split(Regex("\\s+"))
    .filter { it.isNotEmpty() }
    .map {
    it.toInt()
    }
    }
    val screenRecordProcessIds = findProcessIds(processName = "screenrecord")

    View full-size slide

  9. ScreenRecordRule
    9
    class ScreenRecordRule : TestWatcher() {
    private val shell = Shell()
    private var screenRecordProcessIds: List = 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)
    }
    }
    }

    View full-size slide

  10. 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

    View full-size slide

  11. • adbコマンドを使えばAndroidTestの実⾏の様⼦を

    録画できる
    • 実⾏時の様⼦を知って

    テスト失敗時の原因追求ができる
    • 乱⽤するとテスト時間の増⼤に繋がりそう
    • ScreenRecordRuleのソースコード

    https://gist.github.com/mkeeda/30b8cfdcec53859a2cd39cac36d7fc9e
    11
    まとめ
    To Be Continued

    View full-size slide

  12. 参考
    • 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

    View full-size slide