Disable Dagger injection in tests

2019-04-12 04:45发布

问题:

I have the following LoginFragment that uses Dagger to inject its fields:

class LoginFragment : DaggerFragment() {

    @Inject
    lateinit var viewModelFactory: ViewModelProvider.Factory

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)

        viewModel = ViewModelProviders.of(this, viewModelFactory)
                .get(LoginViewModel::class.java)
    }

I also have a corresponding test that mocks the LoginViewModel according to the documentation from Google: "You can create the fragment and provide it a mock ViewModel."

@MediumTest
@RunWith(AndroidJUnit4::class)
class LoginFragmentTest {

    @Mock
    private lateinit var viewModel: LoginViewModel

    @Before
    fun setUp() {
        loginFragment = LoginFragment()

        loginFragment.viewModelFactory = createMockViewModelFactory(viewModel)

        activityRule.activity.setFragment(loginFragment)
    }
}

The problem is that when the onAttached method of the fragment is invoked, Dagger overrides the viewModelFactory with its own object, thus replacing my mock.

How can I prevent Dagger from overriding my mock object?

回答1:

In the android-architecture-components samples on Github Google have an interesting solution.

They inject the activities trough ActivityLifecycleCallbacks. For instrumented tests they use a TestApp that does not register ActivityLifecycleCallbacks so it injects nothing.

Just like in your example the ViewModel.Factory is package private so in the test you can assign it yourself.

For Fragments there is FragmentManager.FragmentLifecycleCallbacks class which can be used. Instead of the Fragment injecting itself in onActivityCreated your production activity injects the Fragment using FragmentLifecycleCallbacks. You can create a testing activity which does not inject the fragment and you can create a mock factory yourself.