I am trying to test fragment interactions using the Android Jetpack Navigation Component and the fragment-testing library. My app is using java + Dagger2 as DI.
To test the navigation I have created a JUnit test:
@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);
}
Whenever I run the test I get following error:
java.util.concurrent.ExecutionException: java.lang.IllegalArgumentException: No injector factory bound for Class<XXX>
How can I inject my fragment there? Is it possible to use DaggerFragments with FragmentScenario
?
IntroFragment
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;
......
}
Declare following function within test class:
@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 = [email protected]
viewModel = [email protected]
// assign other deps here as per your needs
}
}
}, themeResId = R.style.AppTheme)
}
}
Where TestApp
is declared as such:
class TestApp : Application()
This might be needed in order to refrain from error, which will happen in your custom application class's onCreate()
method, where Dagger tree is being constructed.
After having this setup you can start writing your unit test:
@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)
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With