Archie G. Quiñones
Archie G. Quiñones

Reputation: 13688

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?

Upvotes: 2

Views: 1092

Answers (1)

jsamol
jsamol

Reputation: 3232

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.

Upvotes: 5

Related Questions