Espresso Device API を使用して画面構成の変更をテストする

Espresso Device API を使用すると、回転や画面の展開など、デバイスで一般的な構成変更が行われたときにアプリをテストできます。Espresso Device API は、Jetpack Compose テストルールとともにデバイスレベルのアクションを実行する場合におすすめのツールです。Jetpack Compose の UI テストの作成が初めての場合は、Compose レイアウトのテストをご覧ください。

Espresso Device API を使用すると、仮想デバイスで構成の変更をトリガーしてテストを同期的に実行できるため、一度に 1 つの UI アクションまたはアサーションのみが実行され、テスト結果の信頼性が高まります。Espresso を使用した UI テストの作成が初めての場合は、Espresso のドキュメントをご覧ください。

Espresso Device API を使用するには、次のものが必要です。

  • Android Studio Iguana 以降
  • Android Gradle プラグイン 8.3 以降
  • Android Emulator 33.1.10 以降
  • API レベル 24 以降を実行する Android 仮想デバイス

Espresso Device API 用にプロジェクトを設定する

プロジェクトをセットアップして Espresso Device API をサポートするには、次の操作を行います。

  1. テストでテストデバイスにコマンドを渡せるように、androidTest ソースセットのマニフェスト ファイルに必要なネットワーク権限を追加します。

      <uses-permission android:name="android.permission.INTERNET" />
      <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    

    テストのターゲットが Android 17(API レベル 37)以降 の場合は、 ACCESS_LOCAL_NETWORK 権限も宣言する必要があります。

      <uses-permission android:name="android.permission.ACCESS_LOCAL_NETWORK" />
    
  2. gradle.properties ファイルで enableEmulatorControl 試験運用版フラグを有効にします。

      android.experimental.androidTest.enableEmulatorControl=true
    
  3. モジュール レベルのビルド スクリプトで emulatorControl オプションを有効にします。

    Kotlin

      testOptions {
        emulatorControl {
          enable = true
        }
      }
      

    Groovy

      testOptions {
        emulatorControl {
          enable = true
        }
      }
      
  4. モジュール レベルのビルド スクリプトで、Espresso Device ライブラリをプロジェクトにインポートします。

    Kotlin

    dependencies {
      androidTestImplementation("androidx.test.espresso:espresso-device:1.1.0")
    }

    Groovy

    dependencies {
      androidTestImplementation 'androidx.test.espresso:espresso-device:1.1.0'
    }

一般的な構成変更に対するテスト

Espresso Device API には、デバイス構成の変更をトリガーするために使用できる画面の向きと折りたたみ状態が複数あります。次の例は、Compose テストルールを使用して、これらのデバイス状態をトリガーし、結果として得られる UI の変更を検証する方法を示しています。

画面の回転に対するテスト

画面の回転をテストするには、ScreenOrientationRule クラスを使用して、テスト中のデバイスの向きを定義します。

デバイス画面が回転したときにアプリに何が起こるかをテストする例を次に示します。

  1. まず、Compose テストルールを定義し、ScreenOrientationRule クラスを使用して、デバイスを一貫した開始状態(縦向きモードなど)に設定します。

    import androidx.compose.ui.test.assertIsDisplayed
    import androidx.compose.ui.test.assertDoesNotExist
    import androidx.compose.ui.test.junit4.createComposeRule
    import androidx.compose.ui.test.onNodeWithTag
    import androidx.test.espresso.device.EspressoDevice.onDevice
    import androidx.test.espresso.device.action.ScreenOrientation
    import androidx.test.espresso.device.rules.ScreenOrientationRule
    import org.junit.Rule
    import org.junit.Test
    
    class MyConfigurationTest {
    
        // 1. Define the Compose test rule
        @get:Rule
        val composeTestRule = createComposeRule()
    
        // 2. Define the Espresso Device rule for a consistent starting state
        @get:Rule
        val screenOrientationRule = ScreenOrientationRule(ScreenOrientation.PORTRAIT)
    }
    

    テストのターゲットが Android 17(API レベル 37)以降の場合、Espresso Device API には ACCESS_LOCAL_NETWORK 権限が必要です。ScreenOrientationRule ルールを実行する前に、この権限が付与されていることを確認する必要があります。JUnit の RuleChain を使用して、最初に GrantPermissionRule ルールを実行します。

    import androidx.test.rule.GrantPermissionRule
    import org.junit.rules.RuleChain
    
    class MyConfigurationTest {
        val grantPermissionRule = GrantPermissionRule.grant(android.Manifest.permission.ACCESS_LOCAL_NETWORK)
        val composeTestRule = createComposeRule()
        val screenOrientationRule = ScreenOrientationRule(ScreenOrientation.PORTRAIT)
    
        @get:Rule
        val chain = RuleChain
            .outerRule(grantPermissionRule)
            .around(composeTestRule)
            .around(screenOrientationRule)
    }
    
  2. テストの実行中にデバイスを横向きに設定するテストを作成します。

    @Test
    fun myRotationTest() {
      ...
      // Sets the device to landscape orientation during test execution.
      onDevice().setScreenOrientation(ScreenOrientation.LANDSCAPE)
      ...
    }
    
  3. 画面が回転したら、composeTestRule を使用して、コンポーザブルが想定どおりに新しい状態に適応していることを確認します。

    @Test
    fun myRotationTest() {
      ...
      // Sets the device to landscape orientation during test execution.
      onDevice().setScreenOrientation(ScreenOrientation.LANDSCAPE)
      composeTestRule.onNodeWithTag("NavRail").assertIsDisplayed()
      composeTestRule.onNodeWithTag("BottomBar").assertDoesNotExist()
    }
    

画面の展開に対するテスト

折りたたみ式デバイスでアプリが動作しているときに画面が展開された場合に、アプリに何が起こるかをテストする例を次に示します。

  1. まず、onDevice().setClosedMode() を呼び出して、デバイスを折りたたんだ状態でテストします。コンポーザブルがコンパクトな画面幅に適応していることを確認します。

    @Test
    fun myUnfoldedTest() {
      onDevice().setClosedMode()
      composeTestRule.onNodeWithTag("BottomBar").assertIsDisplayed()
      composeTestRule.onNodeWithTag("NavRail").assertDoesNotExist()
      ...
    }
    
  2. 完全に展開された状態に移行するには、onDevice().setFlatMode() を呼び出します。コンポーザブルが拡大されたサイズクラスに適応していることを確認します。

    @Test
    fun myUnfoldedTest() {
      onDevice().setClosedMode()
      ...
      onDevice().setFlatMode()
      composeTestRule.onNodeWithTag("NavRail").assertIsDisplayed()
      composeTestRule.onNodeWithTag("BottomBar").assertDoesNotExist()
    }
    

テストに必要なデバイスを指定する

折りたたみ式ではないデバイスで折りたたみアクションを実行するテストを実行すると、テストが失敗する可能性があります。実行中のデバイスに関連するテストのみを実行するには、@RequiresDeviceMode アノテーションを使用します。テストランナーは、テスト対象の構成をサポートしていないデバイスでのテストの実行を自動的にスキップします。デバイス要件ルールは、各テストまたはテストクラス全体に追加できます。

たとえば、フラット構成への展開をサポートするデバイスでのみテストを実行するように指定するには、次の @RequiresDeviceMode コードをテストに追加します。

@Test
@RequiresDeviceMode(mode = FLAT)
fun myUnfoldedTest() {
  ...
}