测试 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);
因为 TestNavHostController
在 card_list
的 startDestination
上。
实际的失败信息是
expected: 2131296377
but was : 2131296378
at bbct.android.common.navigation.NavigationTest.clickOnSaveNavigatesFromDetailsBackToList(NavigationTest.java:116)
2131296377
是 card_list
的 ID
2131296378
是 card_details
的 ID
- 第116行就是前面提到的
assertThat()
如何强制此测试从正确的目的地开始?或者这不是编写此类测试的正确方法吗?我是否应该首先通过执行用户通常会执行的 UI 操作导航到 card_details
来编写这样的测试?
依赖关系:
以防万一,我有以下导航依赖版本:
navVersion = '2.4.2'
implementation "androidx.navigation:navigation-fragment:$navVersion"
implementation "androidx.navigation:navigation-ui:$navVersion"
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);
});
我有以下导航图 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);
因为 TestNavHostController
在 card_list
的 startDestination
上。
实际的失败信息是
expected: 2131296377
but was : 2131296378
at bbct.android.common.navigation.NavigationTest.clickOnSaveNavigatesFromDetailsBackToList(NavigationTest.java:116)
2131296377
是card_list
的 ID
2131296378
是card_details
的 ID
- 第116行就是前面提到的
assertThat()
如何强制此测试从正确的目的地开始?或者这不是编写此类测试的正确方法吗?我是否应该首先通过执行用户通常会执行的 UI 操作导航到 card_details
来编写这样的测试?
依赖关系:
以防万一,我有以下导航依赖版本:
navVersion = '2.4.2'
implementation "androidx.navigation:navigation-fragment:$navVersion"
implementation "androidx.navigation:navigation-ui:$navVersion"
Just like a real
NavController
, you must callsetGraph
to initialize theTestNavHostController
. In this example, the fragment being tested was the start destination of our graph.TestNavHostController
provides asetCurrentDestination
method that allows you to set the current destination (and optionally, arguments for that destination) so that theNavController
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);
});