androiddagger-2android-fragmentscenario

How to test DaggerFragment with FragmentScenario?


I have a simple Fragment like so:

class SomeFragment : DaggerFragment() {
    ...
}

Now I want to test this Fragment using FragmentScenario

class LoginFragmentTest {

    @Test
    fun test() {
        launchFragmentInContainer<SomeFragment>()
        onView(withId(R.id.someButton))
            .check(matches(isDisplayed()))
    }

}

But everytime I try to the test its always:

java.lang.IllegalArgumentException: No injector was found for <...SomeFragment>

How can I properly run the test? Can anybody help me here?


Solution

  • I found two ways to solve the problem:

    I consider the first approach cleaner and would recommend to use it rather than the latter, but I'll describe both of them, so you can make your own choice.


    Build flavors with typealias

    1. Create two product flavors, mock and prod:

    app/build.gradle

    android {
        ...
        productFlavors {
            prod
            mock {
                applicationIdSuffix '.mock'
            }
        }
    }
    
    1. Then set the typealias depending on the flavor, let's call it BaseFragment:

    prod flavor, app/src/prod/com.example.mypackage/BaseFragment.kt

    typealias BaseFragment = DaggerFragment
    

    mock flavor, app/src/mock/com.example.mypackage/BaseFragment.kt

    typealias BaseFragment = Fragment
    
    1. And finally use the BaseFragment alias in your fragments:
    class SomeFragment : BaseFragment() {
       ...
    }
    
    1. To test the code using FragmentScenario switch from the prod* build variant to the mock* one and set all the dependencies that are supposed to be injected somewhere in your test class (e.g. using mocks)

    Own DaggerFragment and test variants of the fragments

    1. Create your own DaggerFragment (based on the actual dagger.android.support.DaggerFragment implementation):
    abstract class DaggerFragment() : Fragment(), HasAndroidInjector {
    
        @Inject
        lateinit var androidInjector: DispatchingAndroidInjector<Object>
    
        override fun onAttach(context: Context) {
            injectMembers()
            super.onAttach(context)
    
        override fun androidInjector(): AndroidInjector<Object> = androidInjector
    
        protected open fun injectMembers() = AndroidSupportInjection.inject(this)
    }
    
    1. Extend your DaggerFragment implementation and set the fragment open:
    open class SomeFragment : DaggerFragment() {
        ...
    }
    
    1. Create another implementation of your fragment for the test purposes and override the injectMembers method:
    class TestSomeFragment : SomeFragment() {
    
        override injectMembers() {
            /* you can manually inject dependencies and mocks here */
        }
    }
    
    1. Use TestSomeFragment in your tests.