You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android动态功能模块插桩测试如何伪造Dagger依赖注入

动态特征模块Dagger依赖测试替换方案

核心问题是EditNoteActivity内硬编码了正式版EditNoteComponent的初始化逻辑,测试环境下无法介入替换依赖。可按以下三种方案改造,适配动态特征模块的测试注入需求:


方案1:抽象组件工厂,通过Application层暴露组件创建入口

该方案对现有代码侵入性最低,最适配动态模块架构:

  • 先在app主模块定义跨模块的组件工厂接口,避免动态模块直接硬编码Dagger生成类:
// app模块内定义
interface EditNoteComponentProvider {
    fun provideEditNoteComponent(module: EditNoteModule = EditNoteModule()): EditNoteComponent
}
  • 主模块的NoteTakingApplication实现该接口,正式环境下返回正式组件:
open class NoteTakingApplication : Application(), EditNoteComponentProvider {
    lateinit var appComponent: ApplicationComponent
        private set

    override fun onCreate() {
        super.onCreate()
        appComponent = initializeAppComponent()
    }

    open fun initializeAppComponent(): ApplicationComponent {
        return DaggerApplicationComponent.create()
    }

    override fun provideEditNoteComponent(module: EditNoteModule): EditNoteComponent {
        return DaggerEditNoteComponent.builder()
            .applicationModule(appComponent.applicationModule)
            .editNoteModule(module)
            .build()
    }
}

注意:这里不要用DaggerEditNoteComponent.create(),改用builder传入全局的ApplicationModule实例,避免动态模块重复创建app层组件,也更符合Dagger在动态模块的最佳实践

  • 改造EditNoteActivity的注入逻辑,不再硬编码Dagger创建逻辑,而是从Application获取组件:
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    // 从Application获取组件,不再直接引用硬编码的Dagger生成类
    (application as EditNoteComponentProvider)
        .provideEditNoteComponent()
        .inject(this)

    setContent {
        NoteTakingAppTheme {
            EditNoteScreen(
                tutorialText = tutorialText,
                onBackClick = { finish() }
            )
        }
    }
}
  • 测试环境下,覆写测试用Application的组件提供逻辑,传入测试模块即可:
class MyTestApplication : NoteTakingApplication() {
    override fun initializeAppComponent(): ApplicationComponent {
        return DaggerTestApplicationComponent.create()
    }

    override fun provideEditNoteComponent(module: EditNoteModule): EditNoteComponent {
        // 替换为测试专用的EditNoteModule
        return DaggerEditNoteComponent.builder()
            .applicationModule(TestApplicationModule())
            .editNoteModule(TestEditNoteModule())
            .build()
    }
}

配合已实现的MyCustomTestRunner,测试时所有EditNoteActivity的注入都会自动使用测试模块提供的依赖。


方案2:通过Hilt替换原生Dagger,自动适配动态模块测试

如果项目允许迁移依赖注入框架,直接用Hilt是长期维护成本最低的方案:

  • Hilt原生支持动态特征模块的依赖注入,不需要手动管理跨模块的组件生命周期
  • 测试时直接用@BindValue、@TestInstallIn或者自定义TestRule就能替换对应模块的依赖,不需要自定义TestRunner、不需要覆写Application逻辑
  • 不需要在Activity里硬编码组件创建代码,Hilt会自动完成注入

方案3:测试时通过字节码插桩替换硬编码逻辑(零业务代码侵入)

如果不想改现有业务代码,可以在UI测试的build variant里加入专门的构建转换逻辑:

  • 在androidTest的构建配置里,把DaggerEditNoteComponent类替换为测试版本的实现,或者用ASM字节码插桩,修改EditNoteActivity里DaggerEditNoteComponent.create()的调用逻辑,返回传入了TestEditNoteModule的组件实例
  • 该方案不需要改业务代码,但构建配置复杂度高,后续Dagger版本升级、代码混淆时容易出兼容问题,仅适合无法重构业务代码的场景使用。

动态特征模块不要直接用DaggerXxxComponent.create()创建依赖app层的组件,这种写法会导致app层的单例依赖重复创建,也会彻底堵死测试时替换依赖的入口,始终通过全局Application实例持有顶层组件、向下提供子组件是更稳妥的实现方式。

内容的提问来源于stack exchange,提问作者user1105872

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 17:09:17