我有下面的Dagger组件设置,它很适合我的应用程序。
@Singleton
@Component(
modules = [
ApiModule::class,
DatabaseModule::class,
ViewModelModule::class,
ActivityModule::class,
AndroidSupportInjectionModule::class
]
)
interface AppComponent : AndroidInjector<App> {
@Component.Builder
interface Builder {
@BindsInstance
fun application(app: Application): Builder
fun build(): AppComponent
}
}
我希望为ApiModule(Retrofit mock)和DatabaseModule(InMemory Room DB)提供一个自定义实现,以便进行仪器测试。因此,我创建了一个测试组件,如下所示:
@Singleton
@Component(
modules = [
MockApiModule::class,
TestDatabaseModule::class,
ViewModelModule::class,
ActivityModule::class,
AndroidSupportInjectionModule::class
]
)
interface TestComponent : AndroidInjector<App> {
@Component.Builder
interface Builder {
fun build(): TestComponent
}
}
我的片段需要注入ViewModelProvider.Factory
class MovieListingFragment : BaseFragment() {
@Inject lateinit var factory: ViewModelProvider.Factory
private val vm: MovieViewModel by navGraphViewModels(R.id.mobile_navigation) { factory }
我使用ViewModelModule生成的代码如下所示:
@Module
interface ViewModelModule {
@Binds
@IntoMap
@ViewModelKey(MovieViewModel::class)
fun bindMovieViewModel(vm: MovieViewModel): ViewModel
@Binds
fun bindViewModelFactory(factory: ViewModelFactory): ViewModelProvider.Factory
}
如何在测试片段中注入此内容?
@RunWith(AndroidJUnit4::class)
class MovieListFragmentTest {
@Test
fun testMovieListFragment() {
val scenario = launchFragmentInContainer<MovieListingFragment>()
scenario.moveToState(Lifecycle.State.RESUMED)
}
}
1条答案
按热度按时间ruarlubt1#
有很多方法可以实现这一点,但最适合我的方法是创建一个特殊的
mock
buildType,该buildType具有不同的依赖注入设置,用于我不想使用“真实的”的API。然后,我的UI测试将在src/androidTestMock
下运行,以便它运行mock
buildType。您还必须:
1.连接您的API,以便为您的构建类型提供模拟或真实的实现
1.不是在主源代码中而是在每个构建类型中实现非模拟DI设置(例如调试、发布)。这只适用于在您的
mock
构建类型中需要特殊版本的API。在所有构建类型中“真实的存在”的模块将进入您的主源代码。这将导致一些代码重复,如果您真的想这样做,您可以通过使用非模拟源代码集来避免。1.请确保您的模拟类是作为单例提供的,否则您的测试(将执行模拟或不同的测试设置)将收到与您的应用不同的示例。
1.确保CI/CD也是您的模拟构建类型,因为您将主要处理其他构建类型,并且您希望尽早捕获中断的编译。
在您的示例中,
TestComponent
位于src/mock中,AppComponent
位于src/debug和src/release中。