Testowanie nawigacji w Compose

Oddziel kod nawigacji od miejsc docelowych, które można komponować, aby umożliwić testowanie każdego z nich osobno, niezależnie od elementu NavHost.

Nie przekazuj elementu NavController bezpośrednio do żadnego elementu, który można komponować. Zamiast tego przekazuj wywołania zwrotne nawigacji (lambdy) jako parametry. Dzięki temu wszystkie elementy, które można komponować, można testować osobno, ponieważ nie wymagają one instancji elementu NavController w testach.

Lambda composable w elemencie NavHost działa jako pomost między interfejsami API nawigacji a elementem, który można komponować:

@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))
    }
}

Dzięki temu element ProfileScreen można testować niezależnie od nawigacji, przekazując wartości i wywołania zwrotne.

Zalecamy pisanie testów, które obejmują wymagania dotyczące nawigacji w aplikacji, poprzez testowanie elementu NavHost, działań nawigacyjnych przekazywanych do elementów, które można komponować, oraz poszczególnych elementów ekranu, które można komponować.

Testowanie elementu NavHost

Aby rozpocząć testowanie elementu NavHost, dodaj tę zależność testowania nawigacji do pliku build.gradle modułu aplikacji:

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

Umieść element NavHost aplikacji w elemencie, który można komponować, który akceptuje element NavHostController jako parametr:

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

Teraz możesz testować AppNavHost i logikę nawigacji zdefiniowaną w elemencie NavHost przekazując instancję artefaktu testowania nawigacji TestNavHostController.

Test interfejsu, który weryfikuje miejsce docelowe początkowe aplikacji i element NavHost, wygląda tak:

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()
    }
}

Testowanie działań nawigacyjnych

Implementację nawigacji możesz testować na kilka sposobów, klikając elementy interfejsu, a następnie weryfikując wyświetlane miejsce docelowe lub porównując oczekiwaną trasę z bieżącą.

Ponieważ chcesz przetestować konkretną implementację aplikacji, preferowane są kliknięcia w interfejs. Aby dowiedzieć się, jak testować to w izolacji wraz z poszczególnymi funkcjami, które można komponować , zapoznaj się z ćwiczeniem z programowania Testowanie w Jetpack Compose.

Możesz też użyć elementu navController, aby sprawdzić asercje nawigacji, porównując bieżącą trasę z oczekiwaną za pomocą elementu currentBackStackEntry:

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

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

Więcej informacji o podstawach testowania Compose znajdziesz w przewodniku Testowanie układu Compose.