[この記事は Jose Alcérreca、デベロッパー プログラム エンジニア、Wojtek Kaliciński、デベロッパー アドボケートによる Android Developers Blog の記事 "Leveraging product flavors in Android Studio for hermetic testing" を元に翻訳・加筆したものです。詳しくは元記事をご覧ください。]
昨年開催された Android Dev Summitにおいて、テスト コードラボの一部として作成した簡単な Notes アプリケーションの例を取り上げ、Android でのテストの状態について議論しました。テストの不安定性について話し合い、閉じられた環境でのテスト(hermetic testing)をセットアップするための簡易なソリューションを紹介しました。
この問題に対してはよく、閉じられた環境でのテスト、つまり依存関係から隔離されたテストを行うという解決法が取られます。事前に定義されたデータを返す、フェイク実装またはフェイク サーバーの使用は、この問題に対処する一般的な方法のひとつです。好例としては以下のようなものがあります。
依存性の注入(DI)はテストと、モジュールの再利用やモジュールの互換性を促進するソフトウェア設計パターンです。DI フレームワークは、このパターンに関連するボイラープレートの扱いを容易にしますが、DI フレームワークをセットアップして、その動作方法を理解するには長時間を要することもあります。特にプロジェクトの要件がシンプルな場合、アプリにこれらのフレームワークの 1つを適用する前に、より簡単な方法を探るとよいでしょう。
同じメカニズムを活用して、2 つのバージョンのアプリを個別に作成し、閉じられた環境でのテストを支援できます。
手順はシンプルです。
このメソッドを使用して挿入クラスを実装する方法については Android テスト コードラボをご覧ください。これらの実装の 1 つは実際のデータを提供するプロダクトであり、もう 1 つは隔離されたテストの実行にフェイクデータを使用するフェイク依存関係を提供するモックです。
閉じられた環境が適切に設定できたらビルドプロセスに柔軟性をさらにもたせ、アプリのさまざまなコンポーネントを交換できるようにするため、ディメンションを追加してもよいでしょう。上記の方法はシンプルなプロジェクトに適していますが、より複雑な状況では学習のための時間を確保し、依存性の注入フレームワークをプロジェクトに追加することをお勧めします。
Posted by Yuichi Araki - Developer Relations Team
昨年開催された Android Dev Summitにおいて、テスト コードラボの一部として作成した簡単な Notes アプリケーションの例を取り上げ、Android でのテストの状態について議論しました。テストの不安定性について話し合い、閉じられた環境でのテスト(hermetic testing)をセットアップするための簡易なソリューションを紹介しました。
不安定なテストに対処する
障害が発生する、または応答に長時間を要する可能性がある外部依存関係をアプリケーションが有する場合、Espresso や UI Automator のようなフレームワークを使用した UI テストは不安定になりやすいものです。不安定なテストとは、テスト実行の目的自体が無効になるほど信頼性に欠ける(成功または失敗に一定性が見られない)テストのことです。この問題に対してはよく、閉じられた環境でのテスト、つまり依存関係から隔離されたテストを行うという解決法が取られます。事前に定義されたデータを返す、フェイク実装またはフェイク サーバーの使用は、この問題に対処する一般的な方法のひとつです。好例としては以下のようなものがあります。
- ネットワークに接続せず、ディスクに格納されているファイルからデータを素早く返すフェイク API クライアントまたはフェイク サーバーを介して、ネットワークを呼び出すことができます。この方法では、ネットワークの遅延や不安定さ、さらには実際のサーバーに起因するエラーを回避できます。
- 中間インターフェースを介して、低レベル フレームワーク API(特にカメラやストレージなどのハードウェアにアクセスするための API)とのインタラクションを渡すことができます。ハードウェアに依存することなく、このインターフェースのフェイク実装が即座に返され、画像などのプリロード済みのデータへの参照が提供されます。
- GPS、マイク、加速度計などのセンサーもフェイクに置き換えることができ、プリセット位置や操作をシミュレートした入力セットなど、現実世界では実行し難いデータのテストを行えるようになります。
依存性の注入(DI)はテストと、モジュールの再利用やモジュールの互換性を促進するソフトウェア設計パターンです。DI フレームワークは、このパターンに関連するボイラープレートの扱いを容易にしますが、DI フレームワークをセットアップして、その動作方法を理解するには長時間を要することもあります。特にプロジェクトの要件がシンプルな場合、アプリにこれらのフレームワークの 1つを適用する前に、より簡単な方法を探るとよいでしょう。
プロダクト フレーバーで依存関係を管理する
プロダクト フレーバーは Android Studio の強力な機能です。また、Android Gradle プラグインを使用すると、コンパイル時に Java クラスを入れ替えることができ、追加のライブラリが不要になります。一般的なフレーバー ディメンションの例は次のとおりです。- 無料 / 有料フレーバー: ディストリビューション チャネルでリリースされる 2 つの異なる APK を生成する
- 安定 / 実験的: さまざまなソースセットで実験を継続し、ベータ バージョンを素早く生成する
同じメカニズムを活用して、2 つのバージョンのアプリを個別に作成し、閉じられた環境でのテストを支援できます。
- プロダクト - 実際のデータとリソースを用いて、サービスとコンポーネントの実装を使用する
- モック - テスト実行が難しい依存関係のフェイク実装を含むバージョン用
手順はシンプルです。
- app/build.gradle ファイルにフレーバーを作成します。
android {
productFlavors {
mock {
applicationIdSuffix =".mock"
}
prod
}
} - 2 つのディレクトリ app/src/prod と app/src/mock を作成します。
prod/java
フォルダに運用コードに使用するクラスを作成するか、main/java
からクラスを移動します。このクラスがmain/java
フォルダには含まれていないことを確認します。- mock/java フォルダに同じクラスを(厳密に同じクラスおよびファイル名で)作成しますが、テスト用には異なる(フェイク)実装を用意します。
- Android Studio の [Build Variants]ウィンドウでインストールするバリアント、またはテストに使用するバリアントを選択します。バリアントは、フレーバーとビルドタイプの組み合わせです。
installProdDebug
または installMockDebug
を選択する必要があります。 テストを実行する
プロダクト フレーバーとモック フレーバーを構成してモック実装の準備が完了したら、次の Gradle タスクを使用して、テストを実行する方法を選択できます。connectedMockDebugAndroidTest
はandroidTest
ディレクトリとandroidTestMock
ディレクトリを結合し、ソースセットの結果として検出されるテストすべてを実行します。これらのテストは閉じられた環境で実行されるため、テストはより速く、安定性も高まります。送信前のチェックには最適です。connectedProdDebugAndroidTest
は実際の API とセンサーを使用するため、失敗することがあります。継続的インテグレーション システムがある場合、このタスクを毎晩実行させることも、または、受け入れエンドツーエンド テストとして手動で実行することもできます。このタスクは、androidTestProd
が存在しない場合でも、androidTest
でテストを実行することに注意してください。
このメソッドを使用して挿入クラスを実装する方法については Android テスト コードラボをご覧ください。これらの実装の 1 つは実際のデータを提供するプロダクトであり、もう 1 つは隔離されたテストの実行にフェイクデータを使用するフェイク依存関係を提供するモックです。
閉じられた環境が適切に設定できたらビルドプロセスに柔軟性をさらにもたせ、アプリのさまざまなコンポーネントを交換できるようにするため、ディメンションを追加してもよいでしょう。上記の方法はシンプルなプロジェクトに適していますが、より複雑な状況では学習のための時間を確保し、依存性の注入フレームワークをプロジェクトに追加することをお勧めします。
Posted by Yuichi Araki - Developer Relations Team