测试 Android 从任意位置开始的导航

Test Android Navigation starting from arbitrary location

我有以下导航图 startDestination 作为 card_list:

<?xml version="1.0" encoding="utf-8"?>
<navigation xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/nav_graph"
    app:startDestination="@id/card_list">

    <fragment
        android:id="@+id/card_list"
        android:name="bbct.android.common.fragment.BaseballCardList"
        android:label="@string/app_name"
        tools:layout="@layout/card_list">
        <action
            android:id="@+id/action_details"
            app:destination="@id/card_details" />
    </fragment>
    <fragment
        android:id="@+id/card_details"
        android:name="bbct.android.common.fragment.BaseballCardDetails"
        android:label="@string/card_details_title"
        tools:layout="@layout/card_details">
        <argument
            android:name="id"
            app:argType="long" />
    </fragment>
</navigation>

现在我想写一个从card_details:

开始的测试
public class NavigationTest {
    @Test
    public void clickOnSaveNavigatesFromDetailsBackToList() {
        TestNavHostController navController = new TestNavHostController(ApplicationProvider.getApplicationContext());
        FragmentScenario<BaseballCardDetails> listScenario = FragmentScenario.launchInContainer(
            BaseballCardDetails.class,
            null,
            R.style.AppTheme
        );
        listScenario.onFragment(fragment -> {
            navController.setGraph(R.navigation.nav_graph);
            Navigation.setViewNavController(fragment.requireView(), navController);
        });
        assertThat(Objects.requireNonNull(navController.getCurrentDestination()).getId())
            .isEqualTo(R.id.card_details);
        BaseballCard card = new BaseballCard(
            true,
            "Mint",
            "Code Guru Apps",
            1993,
            "1",
            50000,
            1,
            "Code Guru",
            "Code Guru Devs",
            "Catcher"
        );
        BBCTTestUtil.sendKeysToCardDetails(card);
        Espresso.onView(ViewMatchers.withId(R.id.save_button)).perform(ViewActions.click());
        assertThat(Objects.requireNonNull(navController.getCurrentDestination()).getId())
            .isEqualTo(R.id.card_list);
    }
}

失败于

        assertThat(Objects.requireNonNull(navController.getCurrentDestination()).getId())
            .isEqualTo(R.id.card_details);

因为 TestNavHostControllercard_liststartDestination 上。

实际的失败信息是

expected: 2131296377

but was : 2131296378

at bbct.android.common.navigation.NavigationTest.clickOnSaveNavigatesFromDetailsBackToList(NavigationTest.java:116)

如何强制此测试从正确的目的地开始?或者这不是编写此类测试的正确方法吗?我是否应该首先通过执行用户通常会执行的 UI 操作导航到 card_details 来编写这样的测试?


依赖关系:

以防万一,我有以下导航依赖版本:

    navVersion = '2.4.2'
    implementation "androidx.navigation:navigation-fragment:$navVersion"
    implementation "androidx.navigation:navigation-ui:$navVersion"

根据 Testing Navigation guide:

Just like a real NavController, you must call setGraph to initialize the TestNavHostController. In this example, the fragment being tested was the start destination of our graph. TestNavHostController provides a setCurrentDestination method that allows you to set the current destination (and optionally, arguments for that destination) so that the NavController is in the correct state before your test begins.

因此添加对 setCurrentDestination 的调用以在特定目的地初始化您的测试:

listScenario.onFragment(fragment -> {
    navController.setGraph(R.navigation.nav_graph);

    // Create arguments using Safe Args generated classes
    // or construct the Bundle directly
    BaseballCardDetailsArgs args = new BaseballCardDetailsArgs.Builder(0).build();
    Bundle arguments = args.toBundle();

    // Then set the current destination to your card_details
    navController.setCurrentDestination(R.id.card_details, arguments);

    Navigation.setViewNavController(fragment.requireView(), navController);
});