在测试中向目标传递参数



在我的Android应用程序中,我有以下导航图:

<?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接受一个id参数。如果这是-1,那么详细视图将打开,其中包含所有空白字段,并允许用户创建新卡。如果id为正值,则使用它从数据库中获取一行并填充表单以进行编辑。

现在我正在编写一个测试,以验证在编辑卡片时,当用户单击保存按钮时,应用程序导航回card_list:

public class NavigationTest {
@Test
public void clickOnSaveNavigatesFromDetailsBackToList() {
TestNavHostController navController = new TestNavHostController(ApplicationProvider.getApplicationContext());
FragmentScenario<BaseballCardDetails> detailsScenario = FragmentScenario.launchInContainer(
BaseballCardDetails.class,
null,
R.style.AppTheme
);
detailsScenario.onFragment(fragment -> {
navController.setGraph(R.navigation.nav_graph);
BaseballCardDetailsArgs args = new BaseballCardDetailsArgs.Builder(0).build();
navController.setCurrentDestination(R.id.card_details, args.toBundle());
Navigation.setViewNavController(fragment.requireView(), navController);
});
assertThat(Objects.requireNonNull(navController.getCurrentDestination()).getId())
.isEqualTo(R.id.card_details);
Espresso.onView(ViewMatchers.withId(R.id.save_button)).perform(ViewActions.click());
assertThat(Objects.requireNonNull(navController.getCurrentDestination()).getId())
.isEqualTo(R.id.card_list);
}
}

然而,当这个测试导航到card_details时,表单字段没有被卡片的值填充。为了看看发生了什么,我在我的应用程序中添加了Log.d()调用:

public class BaseballCardDetails extends Fragment {
// ...
@Override
public View onCreateView(
@NonNull LayoutInflater inflater,
ViewGroup container,
Bundle savedInstanceState) {
// ...
populateTextEdits();
}
private void populateTextEdits() {
Bundle args = getArguments();
Log.d(TAG, "args: " + args);
// ...
}
}

这个输出

05-31 21:35:13.589 29002 29002 D bbct.android.common.fragment.BaseballCardDetails: args: null

可以看到argsnull。为什么测试中的参数没有传递给这里的片段?更重要的是,我该如何修复它?

当你写:

FragmentScenario<BaseballCardDetails> detailsScenario = FragmentScenario.launchInContainer(
BaseballCardDetails.class,
null,
R.style.AppTheme
);

null是传递给你的片段的参数。因此,getArguments()是空的,因为你已经传递给你的片段的参数是空的。因为NavController没有在你的测试中创建你的片段(相反,它是launchInContainer创建的),你通过setCurrentDestination设置的参数只适用于NavBackEntry的参数(即,如果你调用navController.getCurrentBackStackEntry().getArguments())。

不是将null传递给launchInContainer,而是将argsBundle的构造移到调用launchInContainer之前:

@Test
public void clickOnSaveNavigatesFromDetailsBackToList() {
TestNavHostController navController = new TestNavHostController(ApplicationProvider.getApplicationContext());
// Move args construction here
BaseballCardDetailsArgs args = new BaseballCardDetailsArgs.Builder(0).build();
Bundle bundleArgs = args.toBundle();
// And pass the bundleArgs into launchInContainer:
FragmentScenario<BaseballCardDetails> detailsScenario = FragmentScenario.launchInContainer(
BaseballCardDetails.class,
bundleArgs,
R.style.AppTheme
);
detailsScenario.onFragment(fragment -> {
navController.setGraph(R.navigation.nav_graph);
// Reuse the same bundleArgs here as well
navController.setCurrentDestination(R.id.card_details, bundleArgs);
Navigation.setViewNavController(fragment.requireView(), navController);
});
assertThat(Objects.requireNonNull(navController.getCurrentDestination()).getId())
.isEqualTo(R.id.card_details);
Espresso.onView(ViewMatchers.withId(R.id.save_button)).perform(ViewActions.click());
assertThat(Objects.requireNonNull(navController.getCurrentDestination()).getId())
.isEqualTo(R.id.card_list);
}

最新更新