文章目录DaggerMock让 Dagger 2 的测试不再难写1、 解决什么问题2、 怎么做到的3、 不只是单元测试4、 Kotlin 项目的注意点5、 接入方式6、 谁适合用DaggerMock让 Dagger 2 的测试不再难写DaggerMock 在 GitHub 上拿到 1.1K Star是 fabioCollini 维护的一个 JUnit 规则专门用来解决 Dagger 2 依赖注入框架的单元测试难题。Android 开发里用 Dagger 2 做依赖注入的项目不少但写测试的时候麻烦就来了。要 mock 一个被 Dagger 管理的对象得写一个 TestModule再写一个 TestComponent把原来的模块替掉才能让 mock 生效。一个测试类要写两到三个辅助类代码量比业务逻辑还多。1、 解决什么问题DaggerMock 解决的就是这层样板代码。它是一个 JUnit Rule挂上之后会扫描测试类里所有被 Mock 注解的字段自动生成一个替身模块把原来的 provide 方法覆盖掉。测试代码里只需要在字段上打 Mock剩下的事情规则自己处理。写出来的测试长这样publicclassMainServiceTest{RulepublicDaggerMockRuleMyComponentrulenewDaggerMockRule(MyComponent.class,newMyModule());MockRestServicerestService;MockMyPrintermyPrinter;InjectFromComponentMainServicemainService;TestpublicvoidtestDoSomething(){when(restService.getSomething()).thenReturn(abc);mainService.doSomething();verify(myPrinter).print(ABC);}}Kotlin 版本更短靠DaggerMock.ruleT(module)配合mock()函数几行就够了。2、 怎么做到的背后原理不算复杂。DaggerMock 在运行时动态生成一个继承自原 Module 的子类把里面每个 provide 方法都重写成返回 mock 对象。然后把这个动态 Module 喂给原 Component 构建出新的实例再交还给测试类使用。一个限制是被覆盖的对象必须在 Module 里有对应的 provide 方法。用 Inject 注解直接构造的对象DaggerMock 无能为力。从 0.6 版本开始如果测试类里出现了无法被覆盖的字段类型会直接抛运行时错误避免测试假阳性的情况。3、 不只是单元测试DaggerMock 同时支持 Espresso 和 Robolectric 两种测试场景。Espresso 用例里挂上规则之后可以在 Activity 启动之前就给 mock 设好行为启动之后再做 verify。Robolectric 的用法类似区别在于 Component 是挂到 RuntimeEnvironment 上而不是 Application。子组件subcomponent从 0.6 开始支持但有个前提父组件里创建子组件的方法必须显式接收子组件的 Module 作为参数。如果是用 Binds 注解的抽象方法或者静态方法定义的 ModuleDaggerMock 处理不了这部分对象的替换会失效。Dagger Android 也能用限制更多一些只支持 Espresso 测试subcomponent 和 dependent component 里的对象没法替换并且必须通过customizeBuilder方法手动把 Application 实例塞给 Component 的 Builder。4、 Kotlin 项目的注意点Kotlin 的类默认是 final 的Mockito 没法直接 mock。三种解法把相关类显式标成open缺点是生产代码也跟着开了引入 mockito-inline 或 mock-maker配合 dexopener示例在 RealWorldAppKotlin 模块里用 kotlin-allopen 编译器插件只在编译期给类加 open 修饰示例在 RealWorldAppKotlinAllOpen 模块里第三种方式对生产代码无侵入是 Kotlin 项目里推荐的做法。5、 接入方式DaggerMock 通过 JitPack 分发先在根 build.gradle 加上 JitPack 仓库maven{urlhttps://jitpack.io}模块里加依赖testImplementationcom.github.fabioCollini.daggermock:daggermock:0.8.5androidTestImplementationcom.github.fabioCollini.daggermock:daggermock:0.8.5Kotlin 项目额外加daggermock-kotlin这个 artifact能省掉一些泛型样板代码。6、 谁适合用写 Android 应用、用 Dagger 2 做依赖注入、想要补单元测试的开发者项目里 Module 数量多、每次写测试都要重复造 TestModule 轮子的人Espresso UI 测试里需要 mock 网络层或数据层的场景团队里 Kotlin 类默认 final 导致 Mockito 失效的情况项目本身的代码量不大核心逻辑集中在 DaggerMockRule 这一个类里。读源码能看清楚 JUnit Rule 的工作机制以及如何在运行时通过反射动态替 Dagger 的 Module。对理解 Dagger 的 Component/Module/Component Builder 之间的关系也有帮助。运行时通过反射动态替 Dagger 的 Module。对理解 Dagger 的 Component/Module/Component Builder 之间的关系也有帮助。