如何实现继承编译期不可用类的自定义testInstrumentationRunner
自定义Android测试Runner注入TestApplication的实现方案
需求说明
需要自定义testInstrumentationRunner,重写其newInstance方法接入自定义测试Application,在测试启动阶段跳过GDPR弹窗等非必要流程,保障UI测试稳定运行,预期实现的Runner代码如下:
class UiTestJUnitRunner : AllureAndroidJUnitRunner() { override fun newApplication(cl: ClassLoader, className: String, context: Context): Application { return super.newApplication(cl, TestApplication::class.java.name, context) } }
对应的自定义测试Application代码:
class TestApplication : CoreApplication() { override fun initDebugInfo(): DebugInfo { return DebugInfo.builder() .disableSomeDialogs...() .build() } }
问题卡点
自定义Runner需要继承的AllureAndroidJUnitRunner是Kaspresso库引入的传递依赖,编译阶段类路径不可见,仅在测试执行阶段存在于运行时类路径,可被测试框架正常实例化,但直接编写继承代码会触发编译错误。
已尝试过的方案均未生效:
- 显式通过
androidTestImplementation引入该传递依赖:出现依赖重复问题,运行时生成的实例上下文不互通 - 反射结合字节码操作动态生成Runner类:运行时类加载异常,无法正常启动
- 编写代理Runner,将所有包私有、受保护、公共方法转发给反射生成的目标
testInstrumentationRunner实例:无法被测试框架正常识别启动
可行实现步骤
不需要反射、字节码修改或者代理逻辑,直接用compileOnly作用域引入对应依赖即可解决编译期类不可见、运行时依赖冲突的问题:
- 先查询当前项目中Kaspresso传递引入的Allure依赖版本,在项目根目录执行以下命令查看依赖树:
./gradlew :<你的测试模块名>:dependencies --configuration androidTestRuntimeClasspath
在输出结果中搜索allure-kotlin-android,记录对应的版本号。 - 在测试模块的
build.gradle中添加对应依赖,注意使用androidTestCompileOnly作用域,该作用域的依赖仅参与编译,不会被打包进测试APK,完全不会出现重复依赖问题:
dependencies { // 其余已有依赖保持不变 androidTestCompileOnly "io.qameta.allure:allure-kotlin-android:<上一步查到的版本号>" }
- 直接编写最开始预期的
UiTestJUnitRunner继承逻辑即可,编译可以正常通过,运行时会自动使用Kaspresso自带的Allure Runner实现,不存在上下文不互通的问题。
为了避免后续升级Kaspresso时硬编码的Allure版本号和传递依赖版本不一致导致方法签名不匹配,可以添加Gradle依赖解析规则,自动使用传递依赖的版本,不需要手动维护版本号:
configurations.all { resolutionStrategy.eachDependency { details -> if (details.requested.group == "io.qameta.allure" && details.requested.name == "allure-kotlin-android") { details.useVersion details.target.version } } }
内容的提问来源于stack exchange,提问作者ceedee
相关产品推荐
相关产品推荐

