デバイスファームで出力されるテスト結果とCI/CDサービスでの活用について
はじめに
iOS/Androidの自動テストを実行する環境として端末(実機やエミュレーター)を利用したいケースがあるかと思います。
自動テストは手元だけの実行でなく、CI/CDサービスを通して継続的に実行できるようにしておくことが望ましいです。
その場合、CI/CDサービスからどのように端末に対して自動テストを実行すれば良いでしょうか。
最近は、クラウドのCI/CDサービス(BitriseやCircleCIなど)の利用が増えています。
そのため、CI/CDサービスを通してテストを実行する場合、デバイスファームを利用することになるかと思います。
そこで、本稿ではCI/CDサービスを通してデバイスファームで自動テストを実行した場合について、主に次の2つのことについて書いていきます。
- デバイスファームが出力するテスト結果
- CI/CDサービスによるテスト結果の表示
まず、これらについて書く前に自動テストを実行した際に得られるテスト結果についてかんたんに次に書きます。
自動テストのテスト結果について
手元で自動テストを実行した場合、テスト結果としてどのようなものが出力されるでしょうか。
利用しているライブラリなどによって変化もしますが、主に次のようなものがあります。
- テストの結果が記載されたJUnit.xml形式のファイル
- 各種ログ
- スクリーンショット
JUnit.xml形式のファイルは自動テストでよく利用されていて、次のようなものになります。
<?xml version='1.0' encoding='UTF-8'?>
<testsuites name='LG Nexus 5' tests='4' failures='0' time='1.32'>
<testsuite name='Setup Suite' tests='1' errors='0' failures='0' time='0.66'>
<testcase classname='Setup Suite' name='Setup Test' time='0.66'/>
</testsuite>
<testsuite name='com.example.android.testing.espresso.web.BasicSample.WebViewActivityTest' tests='2' errors='0' failures='0' time='0.35'>
<testcase classname='com.example.android.testing.espresso.web.BasicSample.WebViewActivityTest' name='typeTextInInput_clickButton_ChangesText' time='0.19'/>
<testcase classname='com.example.android.testing.espresso.web.BasicSample.WebViewActivityTest' name='typeTextInInput_clickButton_SubmitsForm' time='0.15'/>
</testsuite>
<testsuite name='Teardown Suite' tests='1' errors='0' failures='0' time='0.31'>
<testcase classname='Teardown Suite' name='Teardown Test' time='0.31'/>
</testsuite>
</testsuites>
このファイルを、CI/CDサービスやテスト結果を保存してくれるサービスなどにわたすことで、成功/失敗したテストの情報や実行時間などがわかります。
---
次にデバイスファームでどのようなテスト結果が得られるかを説明していきます。
デバイスファームが出力するテスト結果
デバイスファームはいろいろありますが、今回はその中から「AWS Device Farm」と「Firebase Test Lab」の2つについて説明をします。
他のデバイスファーム含めた紹介や、各デバイスファームが提供する機能などの説明は別途できればと思います。
また今回のテスト結果はすべてAndroid x Espressoで実行した例を載せています。
AWS Device Farm
出力されるテスト結果
デバイスファームは、複数端末でテストを実行することができます。
AWS Device Farmでは次のように実行した端末単位でテスト結果を見ることができます。
テスト結果としては、次のようにWeb上で「動画」や「ログ(Androidならlogcat、iOSならデバイスコンソールログ)」「パフォーマンスデータ」、そして自動テストで撮っていれば「スクリーンショット(注釈1)」などのテスト結果を見ることができます。 また、「動画」や「ログ」はDLすることができます。
テストケースの成功の有無については、次のように表示されます。
しかし、テスト結果の中にJUnit.xml形式のファイルはなくDLすることはできません。
そのため、APIを通して生成する必要があります。
CI/CDサービスを通して利用する場合
AWS Device FarmをCI/CDサービスを通して利用する場合は、Webブラウザ経由でなくCLIを通しておこなう必要があります。
そのため、APIを通して「テストの実行」と「テスト結果の取得」をおこないます。
それらをサポートしてくれるpluginとして、fastlaneのpluginやGradleのpluginなどがあります。
なお、pluginは「テストの実行」までをサポートし、テストの終了まで待たないものもあります。
テスト結果としては、AWS Device Farmが出力したテスト結果のDLをおこなうだけでは、JUnit.xml形式のファイルはありません。
そこで、テストのアーティファクトを取得して、JUnit.xml形式のファイルを出力するようにする必要があります。
fastlaneのpluginではアーティファクトからJUnit.xml形式のファイルを出力してくれます(最近、この機能を追加しました)。
そのpluginを通して生成されたテスト結果(JUnit.xml形式)の中身は次のような感じです。
<?xml version='1.0' encoding='UTF-8'?>
<testsuites name='LG Nexus 5' tests='4' failures='0' time='1.32'>
<testsuite name='Setup Suite' tests='1' errors='0' failures='0' time='0.66'>
<testcase classname='Setup Suite' name='Setup Test' time='0.66'/>
</testsuite>
<testsuite name='com.example.android.testing.espresso.web.BasicSample.WebViewActivityTest' tests='2' errors='0' failures='0' time='0.35'>
<testcase classname='com.example.android.testing.espresso.web.BasicSample.WebViewActivityTest' name='typeTextInInput_clickButton_ChangesText' time='0.19'/>
<testcase classname='com.example.android.testing.espresso.web.BasicSample.WebViewActivityTest' name='typeTextInInput_clickButton_SubmitsForm' time='0.15'/>
</testsuite>
<testsuite name='Teardown Suite' tests='1' errors='0' failures='0' time='0.31'>
<testcase classname='Teardown Suite' name='Teardown Test' time='0.31'/>
</testsuite>
</testsuites>
testsuites(全体)
- testsuite(クラス単位)
- testcase(その中にあるテストケース)
AWS Device Farmでは情報を細かくとることができるので、上記のような構成にしました(横着をして出してない情報もあります)。
また、端末ごとにテスト結果を出力するようにしています。
Firebase Test Lab
出力されるテスト結果
AWS Device Farm同様に複数の端末で実行できるため、次のように端末単位で結果が表示されます。
テスト結果としては、Web上で次のように「ログ」「動画」そして「パフォーマンス」を見ることができます。
Androidのスクリーンショットについては、別途実装をする必要があります(注釈2)。
テストケースの成功の有無については、次のように表示されます。
これらのテスト結果は、次のような形でGCS(Google Cloud Storage)上に保存されています。 このGCSにあるこれらのテスト結果をすべてダウンロードすることができます。
このテスト結果には、AWS Device FarmではなかったJUnit.xml形式のファイルもテスト結果にあります。
上記の画像であれば「test_result_1.xml」がそれにあたります。
この「test_result_1.xml」の中身は次のような感じです。
<?xml version='1.0' encoding='UTF-8' ?>
<testsuite name="" tests="2" failures="0" errors="0" skipped="0" time="4.041" timestamp="2020-05-16T02:13:23" hostname="localhost">
<properties />
<testcase name="typeTextInInput_clickButton_ChangesText" classname="com.example.android.testing.espresso.web.BasicSample.WebViewActivityTest" time="2.134" />
<testcase name="typeTextInInput_clickButton_SubmitsForm" classname="com.example.android.testing.espresso.web.BasicSample.WebViewActivityTest" time="1.38" />
</testsuite>
このファイルの中身は
testsuite
- testcase
という形をとっています。
これは生成してくれているファイルなので、どのような形式で出力されるかはデバイスファーム側に依存します。
このファイルを見てみると、testcaseにあるtimeの値は2.134と1.38なので、合計すると3.514のはずですが、testsuiteのtimeの値を見ると4.041になっていたりします。
CI/CDサービスを通して利用する場合
Firebase Test LabをCI/CDサービスを通して利用する場合、AWS Device Farm同様にAPIを通して実行することになります。
これらをサポートしてくれるfastlaneのpluginやGradleのpluginがあります。
Firebase Test Labの場合、テスト結果に関してはGCS上にあるテスト結果を取得することになります。
pluginによってどこまで機能をサポートしているかがありますが、テスト結果に関してはGCSからダウンロードをすることによって得られるため、サポートしているケースもあります。
---
ここまでデバイスファームのテスト結果としてどういったものがあるかについて説明をしました。
このテスト結果の中から特にJUnit.xml形式のファイルを利用してどういったことができるかについて次に説明をしていきます。
CI/CDサービスによるテスト結果の表示
デバイスファーム側が出力したテスト結果をどのようにCI/CDサービスで活用すると良いでしょうか。
まず、CI/CDサービスの成果物として、テスト結果を保存しておくというのがあります。 これによりあとで結果を見返すことができます。
また、CI/CDサービスでは生成されたJUnit.xml形式のようなテスト結果を渡すと収集してくれる機能を提供していることが多いです。
---
CI/CDサービスもいろいろとありますが、今回はその中からモバイルアプリでよく利用される「CircleCI」と「Bitrise」の2つについて説明をします。
CircleCI
CircleCIでは生成されたJUnit.xml形式のようなテスト結果を下記のように指定するだけで、テストデータの収集をしてくれます。
- store_test_results:
path: test-results
上記のように指定をすると、ジョブの実行結果のTest Summaryには次のように表示してくれます。
このような1回あたりのテスト結果だけでなく、テストメタデータを渡し続けると、インサイトで履歴含めた情報も見ることができます。
これにより、不安定なテストがなにかといったこともわかります。
このような履歴情報についてはCI/CDサービス自体で提供している場合もありますが、CI/CDサービスと連携する別サービスを活用するという場合もあります(今後、この手の情報の活用は重要になってくると思っています)。
Bitrise
Bitriseでは、テストの結果を見る手段としてAdd-onとしてTest Reportsという機能があります。
Bitriseが提供する自動テストに関するステップ(Xcode Test for iOSやAndroid Unit Testなど)を利用すると、そのジョブ単位のテスト結果を次のように表示してくれます。
上図はFirebase Test Labのステップ(iOS Device Testingなど)を利用した場合に表示される結果です。
詳細を見ると、次のようにFirebase Test Labが出力した情報を見ることができます。
また、サポートしていないステップを使っていても、Test Reportsに結果を出力することはできます。方法としては次のリンク先にあるとおりです。
カスタマイズして結果を表示したい場合は、テストの結果(JUnit.xml形式)が必要になります。
Bitriseがサポートしているステップ以外を使ってデバイスファームを利用する場合は、テスト結果を出力して、自身でTest Reportsを出力させるようにする必要があります。
なお、このTest Reportsは履歴情報を活用してなにかしらの情報を提供するといった機能までは現時点では提供していません。
おわりに
本稿では、デバイスファームでテストを実行した場合のテスト結果と、それをどのようにCI/CDサービスで利用するかについて説明をしました。
最初はテストの成功の有無がわかれば十分だったりしますが、ある程度テストケース数が増えたりしてくると、それらでは不十分になってきます。
このようなテスト結果を活用して、よりよいテスト活動ができればと思います。
蛇足
最近では、JUnit.xml出力形式のファイルをparseしてテスト結果をGitHub StatusやSlack通知時に出すようにしてたりします。
なお、この話は別の記事で書ければと思います。
注釈
(1) AWS Device Farmのスクリーンショットについて
AWS Device FarmのAndroidではスクリーンショットは特定の場所にあるものがテストレポートに追加されます。
(2) Firebase Test Labのスクリーンショットについて
Firebase Test Labが提供しているライブラリを利用することでスクリーンショットを撮ることができます。