Compose ナビゲーションをテストする

Navigation のコードをコンポーザブルのデスティネーションから分離して、NavHost コンポーザブルとは別に、各コンポーザブルを個別にテストできるようにします。

NavController をコンポーザブルに直接渡さないでください。代わりに、ナビゲーション コールバック(ラムダ)をパラメータとして渡します。これにより、テストで NavController のインスタンスが不要になるため、すべてのコンポーザブルを個別にテストできます。

NavHostcomposable ラムダは、Navigation API とコンポーザブルの橋渡しとして機能します。

@Composable
fun ProfileScreen(
    userId: String,
    navigateToFriendProfile: (friendUserId: String) -> Unit
) {
 // …
}

// In your NavHost
composable<Profile> { backStackEntry ->
    val profile = backStackEntry.toRoute<Profile>()
    ProfileScreen(userId = profile.id) { friendUserId ->
        navController.navigate(route = Profile(id = friendUserId))
    }
}

このように、モック値とコールバックを渡すことで、Navigation とは独立して ProfileScreen をテストできます。

NavHost、コンポーザブルに渡されるナビゲーション アクション、個々の画面コンポーザブルをテストすることにより、アプリ ナビゲーションの要件に対応するテストを作成することをおすすめします。

NavHost をテストする

NavHost のテストを開始するには、アプリ モジュールの build.gradle ファイルに次の navigation-testing の依存関係を追加します。

dependencies {
  androidTestImplementation "androidx.navigation:navigation-testing:$navigationVersion"
}

アプリの NavHost を、 NavHostController をパラメータとして受け取るコンポーザブルでラップします。

@Composable
fun AppNavHost(navController: NavHostController){
  NavHost(navController = navController, startDestination = Home){
      composable<Home> { /*...*/ }
      composable<Profile> { /*...*/ }
  }
}

これで、AppNavHostNavHost ナビゲーション テスト アーティファクト TestNavHostController のインスタンスを渡すことで、内部で定義されたナビゲーション ロジックをテストできます。

アプリの開始デスティネーションと NavHost を検証する UI テストは次のようになります。

class NavigationTest {

    @get:Rule
    val composeTestRule = createComposeRule()
    lateinit var navController: TestNavHostController

    @Before
    fun setupAppNavHost() {
        composeTestRule.setContent {
            navController = TestNavHostController(LocalContext.current)
            navController.navigatorProvider.addNavigator(ComposeNavigator())
            AppNavHost(navController = navController)
        }
    }

    @Test
    fun appNavHost_verifyStartDestination() {
        composeTestRule
            .onNodeWithContentDescription("Start Screen")
            .assertIsDisplayed()
    }
}

ナビゲーション アクションをテストする

ナビゲーションの実装は複数の方法でテストできます。UI 要素をクリックして表示されたデスティネーションを検証する方法や、想定されるルートと現在のルートを比較する方法があります。

具体的なアプリの実装をテストする場合は、UI をクリックすることをおすすめします。このテスト方法と、個々のコンポーズ可能な関数を個別にテストする方法については、Jetpack Compose でのテスト Codelab をご覧ください。

navController を使用して、currentBackStackEntry を使用して現在のルートと想定されるルートを比較することで、ナビゲーション アサーションを確認することもできます。

@Test
fun appNavHost_clickProfile_navigatesToProfile() {
    composeTestRule.onNodeWithContentDescription("Go to Profile")
        .performClick()

    assertTrue(navController.currentBackStackEntry?.destination?.hasRoute<Profile>() ?: false)
}

Compose のテストの基本の詳細については、 Compose レイアウトのテストガイドをご覧ください。