どうもこんにちは!
サバ缶(@tech_begin)です。
以下の記事で、テストコードを書く理由について触れました。
☞【初心者向け】よく分からん「テストコード」についてまとめてみた。
初学者向けに解説しているので、ぜひご一読ください!
この記事では、Androidに焦点を当てて、テスト手法について掘り下げていきたいと思います!
Androidにおけるテストの種類
Androidアプリ開発において、テストは2つに分けられます。
- androidTest
- 実際のデバイス、またはエミュレータで実行するテストコードを格納する。
- JVMだけではアプリの機能を検証できない場合に使用する。
- test
- 単体テストなど、ローカルマシンで実行するテストを格納する。
テスト実施のトレードオフ
そしてテストの実施には、3つの方法が挙げられます。
それぞれのメリット/デメリットについても理解しておきましょう!
- 実機デバイス
- 再現性が最も高い
- テストの実施に最も時間がかかる
- 仮装デバイス(AndroidStudio上のエミュレータなど)
- 再現性とテスト速度のバランスを適度に保つことが可能
- スナップショットを利用すると、テスト間でのセットアップ時間を最小限にすることができる
- シミュレートされたデバイス(Robolectricなど)
- 再現性が低い
- テスト速度が早い
スナップショットとは、AVD(Android Virtual Device)の保存されたイメージであり、OS 設定、アプリケーションの状態、ユーザーデータなど、デバイスが保存された時点の全体的な状態を保持する。
テストダブルを使用するかどうか決める
テストを作成する際、以下の2つに分けられます。
- 実際にオブジェクトを作成する方法
- テストダブル(仮のオブジェクトやモックオブジェクトを作成)で行う方法
テストダブルより、前者の方がテストにおいて適切です。
実際に使うデータの方が信頼性高いですからね!
特に以下のような場合は、テストダブルではなく、実際のオブジェクトを使うべきです。
状況に応じて使い分けましょう。
- オブジェクトが、データオブジェクトである
- オブジェクトが実際の依存関係にあるオブジェクトと通信しないと機能しない場合
- オブジェクトの依存関係を複製することが困難である
Android側としては、基本的にモックの使用は最終手段としています。
ただし、以下のような場合はテストダブルを推奨しています。
- 大きなファイルの処理などで時間がかかる
- 任意のポートへの接続など隔離されていないアクション
- 作成するのが難しい構成
テストピラミッドについて
テストには相関関係があります。
- 小規模テスト
- 1つのクラスごとにアプリの動作を検証する単体テスト
- 70%
- 中規模テスト
- モジュール間の相互作用を検証する統合テスト(結合テスト)
- 20%
- 大規模テスト
- アプリの複数のモジュールにまたがって、UI/UXを検証するエンドツーエンドテスト(総合テスト)
- 10%
小規模テストから大規模テストにかけて、各テストの再現性は向上しますが、実行時間・デバッグの労力が増大します。
したがって、大規模テストになるにつれて、テストの数は減らすべきだと言われています。
小規模テスト(単体テスト)について
単体テストは、アプリのテスト戦略の基礎となる、とても重要なものです。
ビルドする度に単体テストを実行すれば、コード修正によって引き起こされるリグレッションを素早く発見し、修正することが可能です。
- ローカルテスト
- ローカルマシンでのみ実行される単体テスト。
- このテストは、Java 仮想マシン(JVM)上でローカルに実行されるようにコンパイルされ、実行時間を最小限に抑えられます。
- テストが Android フレームワークのオブジェクトに依存する場合は、Robolectric の使用をおすすめします。
- 独自の依存関係に依存するテストでは、モック オブジェクトを使用して依存関係の動作をエミュレートします。
- インストゥルメント化テスト
- Android デバイスまたはエミュレータで実行される単体テスト。
- このテストでは、テスト対象アプリの Context などのインストゥルメンテーション情報を利用できます。
- Robolectric のような強力な環境を必要とする、複雑な Android 依存関係を持つ単体テストを実行するには、この方法を使用します。
インストゥルメント化テストを作成する
- AndroidX Test APIを追加する
- JUnit4テストランナー、UIテストAPI(EspressoとUI Automator)が含まれる
- Hamcrestライブラリもある。柔軟にアサーションを作成することができる
いったん、中規模テストと大規模テストは割愛します。
UIテストの自動化について
UIテストでは、アプリが機能要件を満たしているか確認します。
本来は、実際に人が操作して「動作が円滑か」や「操作しやすいデザインになっているか」などを確認します。
しかしそのような作業は時間がかかり、テスト中のミスの恐れもあります。
そこで、UIアクションの実行を自動化した「UIテスト」を作成することをおすすめします。
UIテストを作成するために、フレームワークがいくつかあります。
- 1つのアプリが対象
- UIテストフレームワーク:Espresso
- 特定の操作や、アクティビティに入力した際、期待通りの結果が出力されるか確認します。
- 複数のアプリにまたがる
- UIテストフレームワーク:UI Automator
- 異なるアプリ間、またはアプリとシステム側で連携して正常に動作するかを確認します。
- 例:カメラアプリが、サードパーティ製のSNSアプリに画像共有できるかをテストする
以下では、Android Developers公式サイトで、使い方を解説しています。
☞ユーザー インターフェース テストを自動化する(Android Developers公式)
AndroidJUnitRunner クラス
Android デバイスで JUnit 3 または JUnit 4 形式のテストクラスを実行するためのインストゥルメンテーション ベースの JUnit テストランナーを定義します。
テストランナーを使用すると、テスト パッケージとテスト対象アプリをデバイスまたはエミュレータに読み込み、テストを実行し、結果をレポートする処理が容易になります。
UI Automator API
これを使用すると、フォーカスを持つアクティビティまたはフラグメントとは無関係に、デバイス上の視覚要素を操作できます。
UI Automator でのアプリのテストは、重要なユースケースを扱うために、アプリがシステム UI または別のアプリとやり取りする必要がある場合だけに限定することを推奨しています。
まとめ
テストだけでも、相当奥深いことがご理解いただけたかと思います。
私自身、業務でテストコードを書いていませんでした。
今後はチーム内で提案して、テストの自動化を行っていきたいと思います。
現在執筆中ですが、次は実際にテストを書いてみたいと思います!
乞うご期待!
次におすすめ
最初にもご紹介しましたが、テストコードを書く意義について解説しています。
図解で見やすいように工夫しています!💪
☞【初心者向け】よく分からん「テストコード」についてまとめてみた。