配置dagger-android 2.15后,编写Espresso测试时如何实现Mock?
我之前也踩过这个坑!用普通Dagger2的时候,在Application里握个AppComponent的引用,Espresso测试时直接替换就行,别提多方便了。但换成dagger-android 2.15之后,它把组件初始化的逻辑都隐式处理了,代码是简洁了,可测试的时候想换组件就卡壳了。
先把你提到的Application代码补全下,方便大家理解:
class App : DaggerApplication() { override fun applicationInjector(): AndroidInjector<out DaggerApplication> { return DaggerAppComponent.factory().create(this) } }
下面给你两个亲测有效的解决思路:
方案一:给Application留个“组件替换口子”
最简单的方式就是把组件创建的逻辑抽成可重写的方法,让测试类能轻松替换:
修改你的生产环境App类:
open class App : DaggerApplication() { // 把组件创建逻辑抽成开放方法,默认返回正式组件 open fun buildAppComponent(): AppComponent { return DaggerAppComponent.factory().create(this) } override fun applicationInjector(): AndroidInjector<out DaggerApplication> { return buildAppComponent() } }
然后在测试模块里写个TestApp继承它,返回测试专用的组件:
class TestApp : App() { override fun buildAppComponent(): AppComponent { // 这里返回你提前配置好的测试组件,比如把真实的网络请求换成Mock版本 return DaggerTestAppComponent.factory().create(this) } }
最后别忘了在测试目录的AndroidManifest.xml里指定使用TestApp作为Application,这样跑Espresso测试时就会自动加载测试组件了。
方案二:用测试规则手动替换注入器
如果不想改动生产代码,也可以通过Espresso的测试规则来手动替换组件。不过这个方式需要你给App类加个小口子:
先修改原App类,允许外部设置自定义注入器:
class App : DaggerApplication() { private var customInjector: AndroidInjector<out DaggerApplication>? = null override fun applicationInjector(): AndroidInjector<out DaggerApplication> { // 优先用自定义注入器,没有的话再用默认的正式组件 return customInjector ?: DaggerAppComponent.factory().create(this) } // 给测试用的方法,仅在测试时调用,可加上@VisibleForTesting注解标记 fun setCustomInjector(injector: AndroidInjector<out DaggerApplication>) { this.customInjector = injector } }
然后在测试类里写个自定义测试规则,在启动Activity前替换组件:
class MainScreenTest { @get:Rule val activityRule = object : ActivityTestRule<MainActivity>(MainActivity::class.java, false, false) { override fun beforeActivityLaunched() { super.beforeActivityLaunched() // 获取Application实例 val app = InstrumentationRegistry.getInstrumentation().targetContext.applicationContext as App // 创建测试组件 val testComponent = DaggerTestAppComponent.factory().create(app) // 替换注入器 app.setCustomInjector(testComponent) } } @Test fun testMockDataDisplay() { // 启动Activity activityRule.launchActivity(null) // 这里就可以验证Mock数据的展示逻辑了 } }
小提醒
个人更推荐方案一,因为它的侵入性极低,测试代码和生产代码的边界很清晰,符合测试隔离的原则。方案二适合不想改动生产代码的场景,但要注意用注解标记测试专用方法,避免误用到生产逻辑里。
内容的提问来源于stack exchange,提问作者Albert Gao
相关产品推荐
相关产品推荐

