Tester la navigation Compose

Dissociez le code de navigation de vos destinations de composables afin de pouvoir tester chaque composable séparément, indépendamment du composable NavHost.

Ne transmettez pas NavController directement dans un composable. À la place, transmettez les rappels de navigation (lambdas) en tant que paramètres. Tous vos composables peuvent ainsi être testés individuellement, car ils ne nécessitent pas d'instance de NavController lors des tests.

Le lambda composable de votre NavHost sert de pont entre les API de navigation et votre composable :

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

De cette façon, ProfileScreen peut être testé indépendamment de Navigation en transmettant des valeurs et des rappels fictifs.

Nous vous recommandons d'écrire des tests qui couvrent les besoins de votre application en matière de navigation. Pour ce faire, testez le NavHost, les actions de navigation transmises à vos composables ainsi qu'à vos composables d'écran individuels.

Tester le composable NavHost

Pour commencer à tester votre NavHost, ajoutez la dépendance navigation-testing suivante au fichier build.gradle du module de votre application :

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

Encapsulez le NavHost de votre application dans un composable qui accepte un NavHostController comme paramètre :

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

Vous pouvez maintenant tester AppNavHost et la logique de navigation définie dans NavHost en transmettant une instance de l'artefact de test de navigation TestNavHostController.

Voici à quoi ressemble votre test d'UI qui vérifie la destination de départ de votre application et le NavHost :

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

Tester les actions de navigation

Vous pouvez tester l'implémentation de la navigation de différentes manières : en cliquant sur les éléments de l'UI, puis en vérifiant la destination affichée ou en comparant l'itinéraire attendu par rapport à l'itinéraire actuel.

Pour tester l'implémentation de votre application, il est préférable de tester les clics sur les éléments de l'UI. Pour découvrir comment procéder de manière isolée avec des fonctions composables individuelles, consultez l'atelier de programmation Tests dans Jetpack Compose.

Vous pouvez également utiliser navController pour vérifier les assertions de navigation en comparant la route actuelle à celle attendue, à l'aide de currentBackStackEntry :

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

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

Pour en savoir plus sur les principes de base des tests Compose, consultez le guide Tester votre mise en page Compose.