java - 使用 FragmentScenario 对 Dagger 片段进行单元测试
问题描述
我正在尝试使用 Android Jetpack 导航组件和片段测试库来测试片段交互。我的应用程序使用 java + Dagger2 作为 DI。
为了测试导航,我创建了一个 JUnit 测试:
@Test
public void testNavigationToLoginFragment() {
// Create a mock NavController
NavController mockNavController = mock(NavController.class);
// Create a graphical FragmentScenario for the Intro Fragment
FragmentScenario<IntroFragment> introFragmentScenario = FragmentScenario.launchInContainer(IntroFragment.class);
// Set the NavController property on the fragment
introFragmentScenario.onFragment(fragment ->
Navigation.setViewNavController(fragment.requireView(), mockNavController)
);
// Verify that performing a click prompts the correct Navigation action
onView(withId(R.id.button_login)).perform(click());
verify(mockNavController).navigate(R.id.action_intro_fragment_to_login_fragment);
}
每当我运行测试时,我都会收到以下错误:
java.util.concurrent.ExecutionException: java.lang.IllegalArgumentException: No injector factory bound for Class<XXX>
我怎样才能在那里注入我的片段?是否可以将 DaggerFragments 与 一起使用FragmentScenario
?
介绍片段
public class IntroFragment extends DaggerFragment{
@Inject
CreateQuoteRecyclerViewAdapter createQuoteRecyclerViewAdapter;
@Inject
public ViewModelProvider.Factory factory;
@inject
public MyViewModel viewModel;
.....
}
MyViewModel.java
class CreateOrSignInViewModel extends BaseViewModel() {
@Inject
public CreateOrSignInBindingState state;
......
}
解决方案
在测试类中声明以下函数:
@Config(application = TestApp::class)
@RunWith(AndroidJUnit4::class)
@LooperMode(LooperMode.Mode.PAUSED)
class MyFragmentTest {
private val createQuoteRecyclerViewAdapter: CreateQuoteRecyclerViewAdapter = mock()
private val viewModel: MyViewModel = mock()
private fun launchFragment(): FragmentScenario<MyFragment> {
return launchFragmentInContainer(factory = object : FragmentFactory() {
override fun instantiate(classLoader: ClassLoader, className: String): Fragment {
return MyFragment().apply {
createQuoteRecyclerViewAdapter = this@MyFragmentTest.createQuoteRecyclerViewAdapter
viewModel = this@MyFragmentTest.viewModel
// assign other deps here as per your needs
}
}
}, themeResId = R.style.AppTheme)
}
}
声明TestApp
如下:
class TestApp : Application()
为了避免错误,可能需要这样做,这将发生在您的自定义应用程序类的onCreate()
方法中,其中正在构建 Dagger 树。
完成此设置后,您可以开始编写单元测试:
@Test
fun `navigation to login screen is correctly performed`() {
val navController: NavController = mock()
val scenario = launchFragment()
scenario.onFragment {
Navigation.setViewNavController(it.requireView(), navController)
}
onView(withId(R.id.button_login)).perform(click())
verify(mockNavController).navigate(R.id.action_intro_fragment_to_login_fragment)
}
推荐阅读
- vue.js - “作用域”使 scss 文件和代码不适用于单个 vue 组件
- java - Java 客户端不与远程 TCP 服务器 Android 应用程序形成套接字
- python - 使用 sodapy 客户端时如何修复 Python 中的“ImportError: cannot import name 'Socrata'”错误?
- c++ - 我应该更喜欢类或命名空间范围内的静态 const 变量吗?
- c# - 如何使用 CSOM 将(多个)文件上传到 SharePoint Online?
- powershell - Get-WMIObject 在脚本中返回多个响应,单独运行时只有一个
- html - 使用链接下载 json 文件
- postgresql - 如何在 MacOS 上关闭没有 pg_ctl 的 Postgres 9.6.11?
- c - 调试中的枚举在步骤后没有值
- python - 嵌套字典替换先前的值 + 键而不是附加