Android でテストダブルを使用する

要素やシステムのテスト戦略を策定する際、次の 3 つがある 関連するテストの側面は次のとおりです。

  • スコープ: テストに関係するコードの割合。テストでは、1 つまたは複数の アプリケーション全体、またはその中間にあるかもしれません。「 テスト対象スコープはテスト中であり、一般的に テストだけでなく、テスト対象システムテスト対象ユニットもテストします。
  • 速度: テストの実行速度。テスト速度は、ミリ秒から 数分かかることもあります。
  • 忠実度: どの程度「現実」がテストですか?たとえば、コードの一部に ネットワーク リクエストを実行する必要があり、テストコードは実際に それとも結果が偽装されたものなのか?テストで実際の結果が つまり、忠実度が高くなります。トレードオフは テストの実行に時間がかかり、ネットワークがダウンした場合にエラーが発生する可能性がある。 費用が高くなる可能性があります

テスト戦略の定義方法については、テスト項目をご覧ください。

分離と依存関係

要素または要素システムをテストする場合は、「独立して」行います。対象 たとえば、ViewModel をテストするために、エミュレータを起動して UI を起動する必要はありません。 これは、Android フレームワークに依存しない(または依存しない)ためです。

ただし、テスト対象が機能するかどうかは、他者に依存する可能性があります。対象 たとえば、ViewModel はデータ リポジトリに依存して機能します。

テスト対象に依存関係を提供する必要がある場合は、 テストダブル(テスト オブジェクト)を作成することです。テストダブルは、単一の アプリのコンポーネントとして機能しますが 特定の動作やデータを提供できます主なメリットは、 テストをより迅速かつ簡単に実施できます

テストダブルの種類

テストダブルにはさまざまなタイプがあります。

フェイク 「動作中」状態であるテストダブルテストには適しているものの、本番環境には適さない方法で実装されています。

例: インメモリ データベース。

フェイクはモック フレームワークを必要とせず、軽量です。(推奨)

モック どのように動作するかをプログラムして動作し、そのインタラクションについて期待するテスト double です。モックの相互作用が定義済みの要件と一致しない場合、モックはテストに失敗します。モックは通常、これらすべてを達成するためにモック フレームワークを使用して作成されます。

例: データベース内のメソッドが 1 回だけ呼び出されたことを確認する

スタブ プログラムどおりに動作させるが、その相互作用については期待しないテストダブル。通常はモック フレームワークを使用して作成されます。簡略化のために、スタブよりもフェイクが推奨されます。
ダミー 渡されるものの、使用されないテストダブル。パラメータとして渡すだけの場合などに指定します。

例: クリック コールバックとして渡される空の関数

スパイ 実際のオブジェクトのラッパー。モックと同様に、追加情報も追跡します。これらは通常、複雑さを増すために避けられます。そのため、スパイよりも偽物やモックが好まれます。
シャドウ Robolectric でフェイクが使用されています。

フェイクを使用した例

インターフェースに依存する ViewModel の単体テストを行うとします。 UserRepository と呼ばれ、最初のユーザーの名前を UI に公開します。Google Chat では インターフェースを実装し、既知の情報を返して、疑似テストダブルを作成します。 分析できます

object FakeUserRepository : UserRepository {
    fun getUsers() = listOf(UserAlice, UserBob)
}

val const UserAlice = User("Alice")
val const UserBob = User("Bob")

この架空の UserRepository は、ローカルデータとリモートデータに依存する必要はない ソースを指定します。ファイルがテストソースに存在する 製品版アプリには同梱されません。

<ph type="x-smartling-placeholder">
</ph> 疑似依存関係により、リモート データソースに依存せずに既知のデータを返すことができる
図 1: 単体テストにおける疑似依存関係

次のテストでは、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)
}

単体テストで UserRepository を架空のものに置き換えるのは簡単です。これは、 ViewModel はテスターによって作成されます。しかし、既存のデータウェアハウスを 任意の要素を使用するテストです。

コンポーネントの置換と依存関係インジェクション

テスト対象システムの作成をテストで制御できない場合は、 テストダブルのコンポーネントの置き換えはより複雑になり、 アプリのアーキテクチャをテスト可能な設計に合わせます。

大規模なエンドツーエンド テストであっても、 アプリ内のユーザーフロー全体をナビゲートするインストルメンテーション UI テスト。イン その場合は、テストを密閉型にすることをおすすめします。密閉テストでは インターネットからのデータ取得など、すべての外部依存関係に共通する特徴があります。この 信頼性とパフォーマンスが向上します

<ph type="x-smartling-placeholder">
</ph>
図 2: アプリのほとんどをカバーし、リモートデータを偽造する大規模なテスト

この柔軟性を実現するようにアプリを手動で設計することもできますが、 Hilt などの依存関係インジェクション フレームワークを使用してコンポーネントを置き換える おすすめしますHilt テストガイドをご覧ください。

Robolectric

Android では、Robolectric フレームワークを使用できます。 特別なタイプのテストダブルを提供します。Robolectric を使用すると、Terraform 言語や 継続的インテグレーション環境で 実行できます使用される エミュレータやデバイスのない通常の JVM。視聴回数の増加をシミュレートするため リソースの読み込み、テストダブルによる Android フレームワークのその他の部分 シャドウと呼ばれます。

Robolectric はシミュレータであるため、単純な単体テストに代わるものではなく 互換性テストを行いますスピードを実現し、コストを削減できる 精度が低くなる場合がありますUI テストの優れたアプローチは、 Robolectric テストとインストルメンテーション テストの両方に対応しており、実行するタイミングを決定 機能または互換性をテストする必要性に応じて異なります。Espresso の両方 Compose テストを Robolectric で実行できます。