简体   繁体   中英

Mock jetpack ViewModel for unit tests using Dagger2 (Robolectric)

So I'm trying to write a unit test for my Activity using Robolectric, however I have no idea how to provide a mocked viewmodel seeing as how my vm is instantiated directly in the class. This is due to the fact that jetpack's lifecycle aware ViewModel requires a Provider class to instantiate. So, I'm essentially injecting the custom provider and then using that to create my ViewModel. I've looked at other examples but they all seem extremely confusing. How do I achieve this?

class ActivityEpisodeList : AppCompatActivity() {

        @Inject
        lateinit var vmFactory: ViewModelProvider.Factory

        private lateinit var vm: ActivityViewModel


        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_episode_list)

            MvvmDaggerApp.get(this).appComponent.inject(this)

            vm = ViewModelProviders.of(this, vmFactory)[ActivityViewModel::class.java]
    }
}

This is how I'm creating my ViewModel:

@Module
abstract class ViewModelModule {

    @Binds
    internal abstract fun bindViewModelFactory(factory: ViewModelFactory): ViewModelProvider.Factory

    @Binds
    @IntoMap
    @ViewModelKey(ActivityViewModel::class)
    internal abstract fun postListViewModel(viewModel: ActivityViewModel): ViewModel

}


@Singleton
class ViewModelFactory @Inject constructor(private val viewModels: MutableMap<Class<out ViewModel>, Provider<ViewModel>>) : ViewModelProvider.Factory {

    override fun <T : ViewModel> create(modelClass: Class<T>): T = viewModels[modelClass]?.get() as T
}

@Target(AnnotationTarget.FUNCTION, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER)
@kotlin.annotation.Retention(AnnotationRetention.RUNTIME)
@MapKey
internal annotation class ViewModelKey(val value: KClass<out ViewModel>)

You should inject a Test View Model from the module which appComponent is using to create dependencies here.

Do not create the viewmodel yourself. Create 2 modules for appComponent one which provides the original dependencies and other with test/mock dependencies. Something like this -

@Module
public AppModule {
      public ViewModel appViewModel() { // return original here}
}

  @Module
public TestAppModule extends AppModule {
      public ViewModel appViewModel() { // return test/mock here}
}

In your test when you create Your AppComponent pass TestAppModule instead of AppModule, then you will get mocked dependencies.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM