2019年9月13日(金)にメルカリさんで「Immersive Web Meetup」を開催しました。
9月16日から1週間の日程でTPAC(W3C年次会議)が福岡であり、せっかくの機会なのでTPACに参加されるついでに東京に立ち寄るW3C関係者の方々をお招きして コミュニティに向けてお話をしていていただきたい!と想いを込めて企画しました。2015年にTPACが札幌であったときにもWeb Music Developer [email protected]札幌と題して札幌で開催しています。懐かしいです。

展示も行いました!

映像のXRと音楽のAudio、MIDIという区分で切らず、2つを混ぜ合わせたMeetupにすることで「Immersiveな世界はウェブでも実現できる」をより実感していただくことを意識して展示枠も設けました。そして当日は以下の5つの展示をしていただきました。

  • AR切り絵 - AR Clock Tower, 着せ替え天気予報 by @kageori_w
  • webARであそぶ!デジタルファッション by @saharu54
  • Web360Square by @AtonKish
  • Sound Engine for Web Based Novel Game by @aike1000
  • 音に反応して動くMIDIコンバータ by @sascacci
  • Web360Square by @AtonKish

Meetupでの展示というのは、個人的には初の試みでしたがやはり対象のAPIが「見て、聞いて」という感じるが主体なこともあり、展示場所周辺は人だかりで盛り上がっていました!
なのですが、非常に残念ながら写真撮影を失念、、、、という大失態。写真でのご紹介ができなくて非常に残念です・・・ごめんなさい。

Talk Session

お話をしてくださったのは、Hongchan ChoiChris Wilson、それから羽賀 流登さんの3名です。

「9 Years of Web Audio」 - Hongchan Choi

(スライドはこちら)

Web Audioが最初に実装された2010年から今までの経緯、そしてこれから議論が始まる Audio Device Client の紹介と続きました。 英語ではありますが、スライドにコメントが完璧に書かれているので、詳細はそちらで! 身近で見ていたこともあり、自分自身は、現在に至る歴史、W3Cでのプロセスに関する内容を改めて振り返ると、標準化の難しさ、大変さを改めて感じました。

「WebXR: AR and VR on the Web」 - Chris Wilson

(スライドはこちら)

WebXRのキーとなるピース、そしてウェブでのVR、ARの状況(実装方法も含む)、そしてW3CのでのVR、ARを扱うImmersive Web WGの状況、 そして最後に音がImmersiveを広める大きなキー技術になる。そしてWeb Audioはすでに3Dオーディオが実装されていて、 WebXRを簡単に実装できるThree.jsやA Frame経由でも利用できることが紹介されました。 3Dオーディオも含めて、Three.jsやA Frame経由で手軽に実装できるという点はサクッと作るときにはホントに便利だと感じます。今後、事例が増えることに期待しています。

「PlayCanvasで始めるWebXR」 - 羽賀 流登

WebXRやるならPlayCanvasががとても良い、というお話。実例、またそのデモも含めた内容でした。 第三者が体験しているVRな世界を、各自がもっている端末のブラウザを通して皆で同時に共有して眺めるシステムが非常に印象的で、ここまでできるのか?!とビックリしました。

おわりに

Web Audio、WebXRの両面からのTalk Session、また展示を行うことで「Immersiveな世界はウェブでも実現できる」ことに対して更なる可能性を最も感じていたのは自分自身だったのかもしれません。参加いただいたみなさんも、そうであると嬉しいです。そして自分自身は「ウェブはいい」というのを改めて認識することになりました。
Meetup全体に関しては、WebXRとWebAudio(Music)が一緒にMeetupを行い、展示枠も設けるという初の試みばかりでどうなるのかという心配はありましたが、結果的には「見て、聞いて、感じてもらう」ことが実現できたと感じていてホッとしております。
こういったクロス・コミュニティでMeetupを行い、未来を感じる、というのはホントによいですね!!また機会がありましたら検討したいと思っています。

最後になりましたが、今回会場をご提供いただきましたメルカリさん、そして軽食のスポンサーをしていただきましたGoogleさんには心から感謝申し上げます。ありがとうございました。

左2人目から、Hongchan、Chris、えーじさん
羽賀さん
豪華受付の方々!ありがとうございました!

やっと追加のみんな大好きパンダエクスプレスの「Chow Mein、やきそば、チョーメン」!!
自分で言うのもアレですが、パンダのそれよりも少し上品な味になってるかも😅
BBQとか定番の「ソース焼きそば」に飽きたら是非!我が家も「焼きそば」は「ソース」だったのが、幅が広がりました!
(本家パンダエクスプレスのChow Meinはこちら

焼きそば-ChowMein-チョーメン

これは何?

AndroidアプリをCircleCIでCIする。」のCircleCIをBitriseに変更した時のメモです。
Bitriseの設定のみを書いていこうと思いますので、詳細は「AndroidアプリをCircleCIでCIする。」を御覧ください。

概要

Bitrise

BitriseはCircleCIと同じ種類のクラウド型のCIサービスです。 ロンドンとブダペスト(ハンガリー)にオフィスを持っています。シリコンバレーじゃないのが新鮮でした。

できること

BitriseはiOS、Android、Swift、React Nativeをビルド、テスト、デプロイすることが可能です。本記事では、Androidのビルド、テストをみていきます。

価格

詳しいテーブルはこちらです。小さな組織向けとエンタープライズ向けが用意されてます。 小さな組織向けの1部はこんな感です。(2019年7月現在)

  • Hobby(無料):複数同時ビルドは不可、ビルド時間は10分、月に200回ビルドまで、使えるのは標準マシーン、追加可能なメンバーは2名
  • Developer($36/mo):複数同時ビルドは不可、ビルド時間は45分、ビルド回数は無制限、使えるのは標準マシーン、メンバーの無制限追加可能

さっそく使ってみる

GitHubとBitriseのアカウントが必須ですのでご用意してください。
この記事ではこのリポジトリのコードをサンプルとして使いますので、 ForkもしくはCloneしてリポジトリに追加しておいてください。
それでは追加していきます。

アプリを追加する

下右図のように、ターゲットになるリポジトリを指定してアプリを追加します。

Workflowの設定画面を表示する

アプリの追加が完了すると同時にビルドを走らせてくれます。
が、取り急ぎWorkflowの設定画面を開いてしまいます。プロジェクト名をクリック(下図(1))して 次にWorkflowのタブをクリック(下図(2))して表示します。

タスクを追加する

アプリを追加した状態ではUIテストは追加されませんので、UIテストされるように設定する必要があります。 追加するタスクは以下の2つです。

  • Gradle Runner
  • [BETA] Virtual Device Testing for Android

赤四角の中の2つを追加する。

> Gradle Runnerの追加

Android Unit Test のアイコンの直下にある「+」ボタン(下図(1))をクリックして、「Gradle Runner」で検索すると絞込まれて表示されますので クリックして追加します。(下図(2))

追加すると設定画面が表示されますので以下の2つの四角を変更します。

  • Gradle task to runassembleDebug assembleDebugAndroidTest
  • gradlew file path./gradlew

> [BETA] Virtual Device Testing for Androidの追加

先程追加したGradle Runner の次に追加しますので、直下にある「+」ボタン(下図(1))をクリックして、「[BETA] Virtual」で検索します。すると絞込まれて表示されますので クリックして追加します。(下図(2))

追加すると設定画面が表示されますので以下の2つの四角を変更します。

  • Test devicesPixel2,28,en,portrait
  • Test typeinstrumentation

なお、Test devices はサンプルアプリに minSdkVersion 26 と指定しているので26以上に設定しています。
また、先程変更した Gradle RunnerGradle task to runassembleDebug assembleDebugAndroidTest がデフォルトの assemble のままになっていると テスト用のAPK(app-debug-androidTest.apk)が作成されず、API path で使う環境変数の $BITRISE_APK_PATHapp-release-unsigned.apk等に指定あれてしまい [BETA] Virtual Device Testing for Android が動作できずエラーになりますので、確実に変更するようにしてください。

ちなみに、この [BETA] Virtual Device Testing for Android は「Firebase Test LabでUI Testを実行する」 でも紹介しているのと同じくGCPコマンドから Cloud Testing API(Firebase Test Lab) をラップして使っているようです。

実行する

以上でUI Testまで実行できるようになったはずなので画面内にある [Start/Schedule a Build] ボタンをクリックしてビルドを実行します。

おわりに

ガガっとリポジトリを読んで、設定作ってくれるところは楽チンでよかったですが、 Gradle RunnerGradle task to run 環境変数 $BITRISE_APK_PATH の設定で ハマりました。Firebase Test Labからのエラーメッセージ見られると良いかもな〜、と感じています。

今回のbitrise.yml

今回できあがった bitrise.yml もココに貼っておきます。参考になれば幸いです。

---
format_version: '8'
default_step_lib_source: https://github.com/bitrise-io/bitrise-steplib.git
project_type: android
trigger_map:
- push_branch: "*"
  workflow: primary
- pull_request_source_branch: "*"
  workflow: primary
workflows:
  deploy:
    steps:
    - [email protected]:
        run_if: ''
    - [email protected]: {}
    - [email protected]: {}
    - [email protected]:
        title: Do anything with Script step
    - [email protected]:
        inputs:
        - gradlew_path: "$PROJECT_LOCATION/gradlew"
    - [email protected]:
        inputs:
        - build_gradle_path: "$PROJECT_LOCATION/$MODULE/build.gradle"
    - [email protected]:
        inputs:
        - project_location: "$PROJECT_LOCATION"
        - module: "$MODULE"
        - variant: "$VARIANT"
    - [email protected]:
        inputs:
        - project_location: "$PROJECT_LOCATION"
        - module: "$MODULE"
        - variant: "$VARIANT"
    - [email protected]:
        inputs:
        - project_location: "$PROJECT_LOCATION"
        - module: "$MODULE"
        - variant: "$VARIANT"
    - [email protected]:
        run_if: ''
    - [email protected]: {}
    - [email protected]: {}
  primary:
    steps:
    - [email protected]:
        run_if: ''
    - [email protected]: {}
    - [email protected]: {}
    - [email protected]:
        title: Do anything with Script step
    - [email protected]:
        inputs:
        - gradlew_path: "$PROJECT_LOCATION/gradlew"
    - [email protected]:
        inputs:
        - project_location: "$PROJECT_LOCATION"
        - module: "$MODULE"
        - variant: "$VARIANT"
    - [email protected]:
        inputs:
        - project_location: "$PROJECT_LOCATION"
        - module: "$MODULE"
        - variant: "$VARIANT"
    - [email protected]:
        inputs:
        - gradlew_path: "./gradlew"
        - gradle_task: assembleDebug assembleDebugAndroidTest
    - [email protected]:
        inputs:
        - test_type: instrumentation
        - test_devices: Pixel2,28,en,portrait
    - [email protected]: {}
    - [email protected]: {}
app:
  envs:
  - opts:
      is_expand: false
    PROJECT_LOCATION: "."
  - opts:
      is_expand: false
    MODULE: app
  - opts:
      is_expand: false
    VARIANT: ''

これは何?

AndroidアプリをCircleCIでCIする。」のUI Testの書き方について説明した記事です。 具体的にはサンプルアプリUI Testであるこれの説明です。

概要

AndroidでUI Testを書く

Androidが公式にサポートしているUI Testのツールは EspressoUI Automator の2種類あります。 それぞれ以下の特徴がありますので「どちらを使うか?」については「どちらも併用して使う」のがいいように感じています。

Espresso

「to write concise, beautiful, and reliable Android UI tests」と公式サイトには説明されています。特定のアプリのUIに対してのスクリプトで動作をさせることを可能にするテストフレームワークです。単一のアプリの操作を自動化する場合に使うとよいでしょう。Google社が開発していますので、Anroidの公式のテストツールと言ってよいでしょう。
サンプルアプリではアプリの操作のすべてをEspressoで書いています。

UI Automator

「suitable for cross-app functional UI testing across system and installed apps.」と公式サイトに説明されている通りで、Espressoと比べると、よりAndroidのOSに近い側に位置しているテストフレームワークで、複数アプリを行き来するよう動作をスクリプトで定義することの可能です。Espressoとは違い、複数のアプリの操作を自動化する場合に使うとよいでしょう。こちらもEspressoと同じくGoogle社が開発していますので、Anroidの公式のテストツールと言ってよいでしょう。
サンプルアプリではスクリーンショットの撮影、Permissionリクエストのウィンドウの操作の2つをUI Automatorで書いています。

Espresso、UI AutomatorでTestを書く準備をする

以下の2つのファイルに追加して準備完了です。

build.gradle に以下を追加

....
allprojects {
....
  tasks.matching {it instanceof Test}.all {
    testLogging.events = ["failed", "passed", "skipped"]
  }
....
}
....

> app/build.gradle に以下を追加

....
dependencies {
....
  // for connected Android test
  androidTestUtil 'com.android.support.test:orchestrator:1.0.2'
  androidTestImplementation 'com.android.support.test:runner:1.0.2'
  androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
  androidTestImplementation 'com.android.support.test.espresso:espresso-intents:3.0.2'
  androidTestImplementation 'com.android.support.test.uiautomator:uiautomator-v18:2.1.3'
  androidTestImplementation 'com.android.support.test:rules:1.0.2'
  androidTestImplementation 'junit:junit:4.12'
....
}

テストを書く

テストはapp/src/androidTest/[Package名]以下に書いていきます。
今回のパッケージ名は com.example.uitestsample ですので app/src/androidTest/java/com/example/uitestsample/ 以下にコードを書いていきます。
ファイル作成の粒度はActivity毎、Fragment毎、機能毎等、自由にまとめてしまって問題ありません。 サンプルアプリではActivity毎でまとめてMainActivityInstrumentedTest.ktに書いています。

前準備

@RunWith(AndroidJUnit4::class)
@SdkSuppress(minSdkVersion = 26)
@LargeTest
class MainActivityInstrumentedTest {

    private val _packageName = "com.example.uitestsample"
    private val mUTs: UiTestUtils = UiTestUtils()
    // ^^^ ツールをインスタンス化 ^^^

    @Rule
    @JvmField
    val mActivityTestRule: ActivityTestRule<MainActivity> =
        ActivityTestRule(MainActivity::class.java)

    @Rule
    @JvmField
    val cGrantPermissionRule: GrantPermissionRule =
        GrantPermissionRule.grant(android.Manifest.permission.WRITE_EXTERNAL_STORAGE)
    // ^^^ スクリーンショット保存の為にSTORAGEへのアクセスを強制的に許可 ^^^

    @Rule
    @JvmField
    val screenshotRule = ScreenshotTakingRule(this.mUTs)
    // ^^^ Test失敗時をスクリーンショットを撮影するように指定 ^^^

    @Before
    fun setup() {
        this.mUTs.setActivity(mActivityTestRule.activity)
    }

    @After
    fun teardown() { }

....

}

「Test失敗時をスクリーンショット」の動作は uitestutils/UiTestUtils.kt の最後に定義されています。

....
class ScreenshotTakingRule(mUTs: UiTestUtils) : TestWatcher() {
    private var mUTs = mUTs

    override fun failed(e: Throwable?, description: org.junit.runner.Description?) {
        super.failed(e, description)
        val path = mUTs.screenShot("FAIL-$description")
        mUTs.log_d(">>> !!! TEST FAILED !!! <<< ScreenShot Taken method=[$description] filename=[$path]")
    }
}

テストケース

サンプルアプリではテストケースは以下の3つです。 「ケースとして足りない!」とかツッコミはありかもしれませんが、UI Testを動かすことを目的としていますのでご容赦ください。

  • useAppContext():テストしているアプリのパッケージ名を確認
  • checkTextHelloWorld():アプリ起動時、中心の「Hello World!」の表示を確認
  • checkButtonIncrementFloating():画面右下のボタンをタップすると表示している数字がカウントアップしSnackbarが表示され、またメニューからResetするとゼロになることを確認

checkButtonIncrementFloating() のポイントをインラインで説明します。
Testのコード全体はこちらになりますので合わせて御覧ください。

....
@Test
fun checkButtonIncrementFloating() {
    // false にすることでTestが成功した場合でもスクリーンショットを残せます。
    // デフォルトでは、Testが成功するとスクリーンショットは全削除となります。
    this.mUTs.prepareScreenShot(false)

....

    val willTap = 5
    // 右下の赤色のFabを指定
    val incrementButton =  withId(R.id.increment_fab_text)

    // カウンターを増加させて表示が想定通りであるか確認する
    for(i in 1..willTap) {
        // スクリーンショットを撮影
        mUTs.screenShot("", "BEFORE >>> カウンター:インクリメント IDX=[$i]")
        // 指定した赤色のFabをタップ
        onView(incrementButton).perform(click())

        // Permissionリクエストが出てたら許可(このテスト中は出ないはず)
        mUTs.allowPermissionsIfNeeded()

        // スクリーンショットを撮影
        mUTs.screenShot("", "AFTER >>> カウンター:インクリメント IDX=[$i]")
        // 要素内の文字列を取得
        actualCount = this.mUTs.getText(withId(R.id.main_content_text))
        // ログを残す
        this.mUTs.log_d("[Counter SEQ] 🍏🍎 expected=[$i] actual=[$actualCount]")
        // 文字列をAssert
        assertEquals("[Counter SEQ] 🍏🍎", i.toString(), actualCount)

        // Snackbarの文言チェック
        val snackBarTapped = allOf(withId(android.support.design.R.id.snackbar_text), withText("Tapped $i times."))
        // Snackbarがから消えるのを待つ
        waitForSnackbarDisappear(snackBarTapped)
        // Sleepする
        this.mUTs.sleep("SHR")
    }

....

    // this.mUTs.prepareScreenShot() に false をセットしていなければ
    // スクリーンショットを削除する()
    this.mUTs.removeSuccessScreenShots()

....

}
....

IDが指定されていないエレメントの指定方法

エレメントに対してIDが振られている場合は大抵の場合そのIDを使うことで指定することが可能ですが、 指定されていない場合は Layout Inspector公式ドキュメント)で階層構造を取得 して解析をしてから、以下のように指定を行います。

Fragmentの重なり方が操作によって変化する場合があり、表示は同じでも階層が違う場合が多々発生します。 ですので、Layout Inspectorで階層構造を取得するときはUI Testでのシナリオ通りに一度画面を遷移させて、それから取得すると良いでしょう。

おわりに

iOS標準のUI TestツールであるXCTestに比べると 癖が少し強いです。とっつきにくいところもありますが、そこまで難しくはないので気になっている場合は挑戦してみてください。
自分の作ったアプリが自動で動くのを見るのも楽しいと思います。

Reference

これは何?

AndroidアプリをCircleCIでCIする。」のUI TestをCircleCIから実行する方法について説明した記事です。 サンプルアプリのUI Testを走らせるFirebase Test Lab(UI Testを実行するインフラ)について解説していきます。

概要

Ciの流れでUI Testが実行されている箇所

AndroidアプリをCircleCIでCIする。」のCIの流れでは (3) UI Test でUI Testを実行、 (4) Report でレポートアップロードしています。

ここで使うコードは以下の通りです。

ポイント、条件など

CIで使うCircleCIは2.0からAndroidのエミュレータを動かすことができなくなったことから、 CircleCI単体でのUI Testの実行が不可能になりました。(公式ドキュメント) ですので、UI Testを含めるとすると、AndroidアプリのCIは外部サービスを利用することが必須となっています。

今回は公式ドキュメントにオススメされている Firebase Test Labを使うことにしました。

Firebase Test Labとは

Firebase Test LabはFirebaseがのサービスの1つとして提供しているクラウドでUI Testを行うプラットフォームです。Android(Espresso、UI Automator)、iOS(XCTest)で書かれたテストの実行に対応しています。

(詳しくは「AndroidアプリをCircleCIでCIする。」のFirebase Test Labとはを御覧ください。)

公式ドキュメントはこちらです。

それではアカウント等の準備を説明します。

料金体系(2019年7月現在)

料金は無料枠が、物理デバイスでのテスト実行5回まで、Virtual(仮想)デバイスでのテスト実行10回まで。
無料枠を超えると、物理デバイス1台1時間$5、Virtual(仮想)デバイス1台1時間$1となります。 また、テスト実行時間の上限もあり、物理デバイスが30分、Virtual(仮想)デバイスが60分と決められていますので、 Firebase Test Labでテストを実行する場合はそこに収まるようにテストケースを考えましょう。
この時間はデフォルトでは物理デバイスもVirtual(仮想)デバイスも同じく15分で設定されています。

詳細はここのTest Labの項目を御覧ください。

> Firebaseのアカウントの準備

console.firebase.google.comからアカウントを作成します。

> GCPのアカウントとプロジェクトを準備

Circle CIからは gcloud コマンドを使って Firebase Test Lab 実行するので、GCPのアカウントも必須となります。 またプロジェクトの必要となりますので作成していきます。

続いて、gcloud コマンドはこの公式ドキュメントの通りインストールを行ってください。
最後にAndroidのBuild環境をセットアップしてください。Android Studioをインストールするのがよいと思います。

> コマンドから動かしてみる

まずは、ターゲットのプロジェクトを指定を行います。

# コマンドラインでGCPにログイン
$ gcloud auth;

# 設定可能なプロジェクトをリストする
$ gcloud projects list;
PROJECT_ID                 NAME                   PROJECT_NUMBER
my-test-project-00-2xxxx5  My-Test-Project-00     6xxxx4xxxxx6

# 「my-test-project-00-24690」をプロジェクトとして指定する
$ gcloud config set project my-test-project-00-2xxxx5;

# 設定内容を確認する(account, projectが指定した内容であるか確認)
$ gcloud config list;
[compute]
region = us-central1
zone = us-central1-c
[core]
account = [email protected]
disable_usage_reporting = True
project = my-test-project-00-2xxxx5

Your active configuration is: [default]

> ローカルで動作させてみる

# コードをCloneする
$ git clone https://github.com/ryoyakawai/uitest_sample_android.git;
$ cd uitest_sample_android/;

# Build
# Emulatorが動作していない場合エラーとなりますが、以下の2つが生成されていればOKです。
# - app/build/outputs/apk/debug/app-debug.apk
# - app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk
$ ./gradlew connectedAndroidTest;

# 環境変数を指定する
$ GOOGLE_PROJECT_ID="my-test-project-00-2xxxx5";
$ BK_OBJ_NAME="${GOOGLE_PROJECT_ID}/uitest-$(date "+%Y%m%d_%H%M")";

# コマンドを改行するときは末尾のスペースを忘れずに入れてください。
$ gcloud firebase test android run \
 --type instrumentation \
 --app ./app/build/outputs/apk/debug/app-debug.apk \
 --test ./app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk \
 --test-targets "class com.example.uitestsample.MainActivityInstrumentedTest" \
 --results-dir $BK_OBJ_NAME \
 --results-bucket cloud-test-${GOOGLE_PROJECT_ID} \
 --directories-to-pull /sdcard/uitest/ \
 --device model=Pixel2,version=26,locale=en_US,orientation=portrait \
 --use-orchestrator \
 --timeout 120s;

# 無事に開始されると以下が出力さる
Have questions, feedback, or issues? Get support by visiting:
  https://firebase.google.com/support/

Uploading [./app/build/outputs/apk/debug/app-debug.apk] to Firebase Test Lab...
Uploading [./app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk] to Firebase Test Lab...
Raw results will be stored in your GCS bucket at [https://console.developers.google.com/storage/browser/cloud-test-my-test-project-00-2xxxx5/my-test-project-00-2xxxx5/uitest-20190716_1603/]

Test [matrix-1gpbgxrsx8fag] has been created in the Google Cloud.
Firebase Test Lab will execute your instrumentation test on 1 device(s).
Creating individual test executions...done.

Test results will be streamed to [https://console.firebase.google.com/project/my-test-project-00-2xxxx5/testlab/histories/bh.xxxxxxxxxxxx/matrices/8xxxxxxxxxxxx11].
16:17:55 Test is Pending
16:18:23 Starting attempt 1.
16:18:23 Test is Running
16:19:17 Started logcat recording.
16:19:17 Preparing device.
16:19:52 Logging in to Google account on device.
16:19:52 Installing apps.
16:20:06 Retrieving Pre-Test Package Stats information from the device.
16:20:06 Retrieving Performance Environment information from the device.
16:20:06 Started crash detection.
16:20:06 Started crash monitoring.
16:20:06 Started performance monitoring.
16:20:19 Started video recording.
16:20:19 Starting instrumentation test.
16:20:53 Completed instrumentation test.
16:21:07 Stopped performance monitoring.
16:21:14 Stopped crash monitoring.
16:21:14 Stopped logcat recording.
16:21:14 Retrieving Post-test Package Stats information from the device.
16:21:14 Logging out of Google account on device.
16:21:21 Done. Test time = 36 (secs)
16:21:21 Starting results processing. Attempt: 1
16:21:28 Completed results processing. Time taken = 6 (secs)
16:21:28 Test is Finished

Instrumentation testing complete.

More details are available at [https://console.firebase.google.com/project/my-test-project-00-2xxxx5/testlab/histories/bh.xxxxxxxxxxxx/matrices/8xxxxxxxxxxxx11].
┌─────────┬──────────────────────────┬─────────────────────┐
│ OUTCOME │     TEST_AXIS_VALUE      │     TEST_DETAILS    │
├─────────┼──────────────────────────┼─────────────────────┤
│ Passed  │ Pixel2-26-en_US-portrait │ 3 test cases passed │
└─────────┴──────────────────────────┴─────────────────────┘

コマンドに出力されるFirebaseのURLにアクセスすると結果が見られます。以下の1行のように表示されているはずで、ブラウザからアクセスすると下図が表示されます。

Test results will be streamed to [https://console.firebase.google.com/project/my-test-project-00-2xxxx5/testlab/histories/bh.xxxxxxxxxxxx/matrices/8xxxxxxxxxxxx11]

静止画、動画を一覧で表示することができるので、テストで何がされていたかも後から確認することが可能です。 ちなみに、デフォルトで動画は撮影してくれる設定になっていますが、静止画に関しては自前で撮影する処理を書き、タイミングを決めてテストスクリプトに埋め込む必要があります。 テスト失敗時の静止画も自前で設定する必要がありますが、今回のサンプルアプリのUiTestUtilsに含んでいますので試してみたい場合は利用してみてください。

おわりに

CIの流れの中ではもちろん、また「日々の開発と並行してテストしたい場合にローカルで環境を用意する」ことはコスト的に厳しかったり、 「他端末の実デバイスを使ってまずはテストを動かしてみたい」というのも同じくコスト的に厳しいことが少なくないと思います。 全ては無理かもしれませんが、そんなときに心配の塊の1部だけでも取り除くべきFirebase Test Labを使う、というのもとても有効だと思います。
気になっている方は使ってみてはいかがでしょうか?

Reference