在测试期间,我的视图模型仍在使用生产服务,我希望他们使用测试服务。我正在使用robolectric进行测试,但仍然没有找到解决我问题的方法。
我认为最有希望的是在测试片段中使用viewModelFactory生成器,例如GitHubBrowserSample中使用了ViewModelUtil.createFor(mockedViewModel)
。但这对我不起作用,如下所示,在运行startFragment
时,在模拟的viewModel中创建的测试服务将被生产服务替换。
我的主应用程序扩展了DaggerApplication(),并且我的生产组件使用@ Component.Builder,所以我无法在构建过程中指定模块。
此外,我尝试将TestAppComponent
从我的AppComponent
扩展出来,但这似乎也不起作用。
我还尝试过将构建器设置为MyApplication.kt中的静态对象,如下所示:
companion object {
var builder: AndroidInjector.Factory<MyApplication> =
DaggerAppComponent.builder()
}
...
override fun applicationInjector(): AndroidInjector<out DaggerApplication> {
return builder.create(this)
}
然后在我的FragmentTest.kt init中执行以下操作:
private fun init() {
bagFragment = BagFragment.newInstance()
MyApplication.builder = DaggerTestAppComponent.builder()
SupportFragmentTestUtil.startFragment(bagFragment, AppCompatActivity::class.java)
}
但是由于类型不匹配而无法正常工作。如果有某种解决方案仍然有可能从DaggerApplication()进行扩展,我对此会非常感兴趣。
这是我的设置:
AppComponent.kt
@Singleton
@Component(modules = [
AndroidInjectionModule::class,
AndroidSupportInjectionModule::class,
AppModule::class,
ActivityModule::class,
FragmentModule::class,
ProductionModule::class])
interface AppComponent : AndroidInjector<MyApplication>{
@Component.Builder
abstract class Builder : AndroidInjector.Builder<MyApplication>()
}
ProductionModule.kt
@Module
open class ProductionModule {
@Provides
fun browseCategoriesViewModel(authenticationService: AuthenticationService): BrowseCategoriesFragment.BrowseCategoriesViewModel{
return BrowseCategoriesFragment.BrowseCategoriesViewModel(authenticationService)
}
// Provides multiple things
...
ViewModelModule.kt
@Module
abstract class ViewModelModule {
@Binds
abstract fun bindViewModelFactory(factor: ViewModelFactory): ViewModelProvider.Factory
/*** Fragments ***/
@Binds
@IntoMap
@ViewModelKey(BagFragment.BagViewModel::class)
abstract fun bindBagViewModel(viewModel: BagFragment.BagViewModel): ViewModel
MyApplication.kt
class MyApplication: DaggerApplication(), HasActivityInjector, HasSupportFragmentInjector {
@Inject
lateinit var sharedPreferencesService: SharedPreferencesService
@Inject
lateinit var activityInjector: DispatchingAndroidInjector<Activity>
@Inject
lateinit var supportFragmentInjector: DispatchingAndroidInjector<Fragment>
override fun attachBaseContext(base: Context?) {
super.attachBaseContext(base)
MultiDex.install(this)
}
override fun applicationInjector(): AndroidInjector<out DaggerApplication> {
return DaggerAppComponent.builder().create(this)
}
override fun activityInjector() = activityInjector
override fun supportFragmentInjector() = supportFragmentInjector
}
AppModule,FragmentModule和ActivityModule是根据文档设置的,没有给我任何问题。
这是我的测试设置:
TestAppComponent.kt
@Singleton
@Component(modules =[
AndroidInjectionModule::class,
AndroidSupportInjectionModule::class,
TestModule::class])
interface TestAppComponent: AndroidInjector<MyApplication>{
@Component.Builder
abstract class Builder: AndroidInjector.Builder<MyApplication>()
}
TestModule.kt
@Module
internal class TestModule {
@Provides
fun bagViewModel(dataService: FakeDataService,
authenticationService: FakeAuthenticationService,
favoritesService: FakeFavoritesService,
cartService: FakeCartService): BagFragment.BagViewModel {
return BagFragment.BagViewModel(dataService, authenticationService, favoritesService, cartService)
}
@Provides
@Singleton
fun dataService(): FakeDataService = FakeDataService()
@Provides
@Singleton
fun authenticationService(): FakeAuthenticationService = FakeAuthenticationService()
// provides many other things
我当前的测试片段初始化方法如下:
private fun init() {
bagFragment = BagFragment.newInstance()
SupportFragmentTestUtil.startFragment(bagFragment, AppCompatActivity::class.java)
}
最后但并非最不重要的一个示例生产片段:
BagFragment.kt
@Inject
lateinit var viewModelFactory: ViewModelProvider.Factory
lateinit var viewModel: BagViewModel
override fun onCreate(savedInstanceState: Bundle?) {
AndroidSupportInjection.inject(this)
super.onCreate(savedInstanceState)
viewModel = ViewModelProviders.of(this, viewModelFactory).get(BagViewModel::class.java)
}
当我打电话给SupportFragmentTestUtil.startFragment()
时,我假设AndroidInjection.inject(this)
将用生产模块替换我的假测试模块。我还尝试过将AndroidInjection.inject(this)
放在init
方法中,而不是onCreate
中,但这给我带来了其他问题,并且与文档相反。请帮忙!