要素または要素のシステムをテストする場合は、個別にテストします。たとえば、ViewModel をテストするために、エミュレータを起動して UI を起動する必要はありません。これは、ViewModel が Android フレームワークに依存していないためです(依存すべきでもありません)。
ただし、テスト対象の機能が動作するために他の機能に依存している場合があります。たとえば、ViewModel はデータ リポジトリに依存して動作する場合があります。
テスト対象に依存関係を提供する必要がある場合は、テストダブル(テスト オブジェクト)を作成するのが一般的な方法です。テスト ダブルは、アプリ内のコンポーネントのように見え、動作するオブジェクトですが、特定の動作やデータを提供するためにテスト内で作成されます。主な利点は、テストをより迅速かつ簡単にできることです。
テストダブルの種類
テスト ダブルにはさまざまな種類があります。
偽装 | クラスの「機能する」実装を持つテストダブルであるものの、テストには適しているが本番環境には適さない方法で実装されている。
例: インメモリ データベース。 フェイクはモック フレームワークを必要とせず、軽量です。(推奨)。 |
---|---|
モック | プログラムされたとおりに動作し、インタラクションに関する期待値を持つテストダブル。モックのインタラクションが定義した要件と一致しない場合、モックのテストは失敗します。モックは通常、これらすべてを達成するためにモック フレームワークを使用して作成されます。 例: データベース内のメソッドが 1 回だけ呼び出されたことを確認します。 |
スタブ | プログラムどおりに動作させるが、そのインタラクションについては期待しないテストダブル。通常は、モック フレームワークを使用して作成します。単純にするため、スタブよりもフェイクを優先します。 |
ダミー | 渡されるが使用されないテストダブル(パラメータとして指定する必要がある場合など)。 例: クリック コールバックとして渡される空の関数。 |
スパイ | 実際のオブジェクトをラップし、モックと同様に追加情報を追跡します。これらは通常、複雑さを増すために避けられます。そのため、スパイよりもフェイクまたはモックが推奨されます。 |
シャドウ | Robolectric でフェイクが使用されています。 |
フェイクを使用した例
UserRepository
というインターフェースに依存し、最初のユーザーの名前を UI に公開する ViewModel の単体テストを行うとします。インターフェースを実装して既知のデータを返すことで、偽のテストダブルを作成できます。
object FakeUserRepository : UserRepository {
fun getUsers() = listOf(UserAlice, UserBob)
}
val const UserAlice = User("Alice")
val const UserBob = User("Bob")
この偽の UserRepository
は、本番環境バージョンで使用するローカル データソースとリモート データソースに依存する必要はありません。このファイルはテストソースセットに存在し、本番環境のアプリには同梱されません。
次のテストでは、ViewModel が最初のユーザー名をビューに正しく公開することを確認します。
@Test
fun viewModelA_loadsUsers_showsFirstUser() {
// Given a VM using fake data
val viewModel = ViewModelA(FakeUserRepository) // Kicks off data load on init
// Verify that the exposed data is correct
assertEquals(viewModel.firstUserName, UserAlice.name)
}
ViewModel はテスターによって作成されるため、単体テストでは UserRepository
を偽物に置き換えることができます。ただし、大規模なテストでは任意の要素を置き換えるのが困難な場合があります。
コンポーネントの置き換えと依存関係の注入
テストでテスト対象システムの作成を制御できない場合、テストダブルのコンポーネントの置き換えが複雑になり、アプリのアーキテクチャがテスト可能な設計に従う必要があります。
大規模なエンドツーエンド テストでも、アプリの完全なユーザーフローをナビゲートするインストルメンテーション UI テストなど、テストダブルを使用するとメリットがあります。その場合は、テストを気密性の高いものにすることをおすすめします。密閉型テストでは、インターネットからデータを取得するなど、すべての外部依存関係を回避します。これにより、信頼性とパフォーマンスが向上します。
この柔軟性を手動で実現するようにアプリを設計することもできますが、Hilt などの依存関係の挿入フレームワークを使用して、テスト時にアプリ内のコンポーネントを置き換えることをおすすめします。Hilt テストガイドをご覧ください。
次のステップ
[テスト戦略] ページでは、さまざまな種類のテストを使用して生産性を向上させる方法について説明します。