如何在Android Instrumentation Tests中兼容Hilt与非Hilt测试
如何配置Android Instrumentation Tests同时支持Hilt与非Hilt测试
问题背景
原本可正常运行的Jetpack Compose + Espresso测试,在按照谷歌Hilt测试指南添加HiltTestRule并配置自定义CustomTestRunner后,Hilt测试能正常执行,但使用createAndroidComposeRule的非Hilt测试抛出以下错误:
java.lang.IllegalStateException: The component was not created. Check that you have added the HiltAndroidRule.
问题根源在于自定义的CustomTestRunner强制所有测试使用HiltTestApplication,代码如下:
class CustomTestRunner : AndroidJUnitRunner() { override fun newApplication(cl: ClassLoader?, name: String?, context: Context?): Application { return super.newApplication(cl, HiltTestApplication::class.java.name, context) } }
此前尝试的两种方案均无效:
- 无法配置多个
testInstrumentationRunner,也无法直接从测试向defaultConfig传递标记 - 尝试通过
runnerArgs判断测试注解,但runnerArgs为私有属性,子类无法访问
可行解决方案
方案1:通过反射识别测试注解,动态选择Application
修改CustomTestRunner,利用反射获取当前运行的测试类,判断是否带有Hilt测试注解(如@HiltAndroidTest),动态决定使用的Application:
class CustomTestRunner : AndroidJUnitRunner() { override fun newApplication(cl: ClassLoader?, name: String?, context: Context?): Application { // 获取当前测试类的全限定名 val testClassName = System.getProperty("android.junit.class") return testClassName?.let { val testClass = Class.forName(it, false, cl) // 仅对标记@HiltAndroidTest的测试使用HiltTestApplication if (testClass.isAnnotationPresent(HiltAndroidTest::class.java)) { super.newApplication(cl, HiltTestApplication::class.java.name, context) } else { // 非Hilt测试使用项目原本的Application super.newApplication(cl, MyApp::class.java.name, context) } } ?: super.newApplication(cl, HiltTestApplication::class.java.name, context) } }
这样只有标记了@HiltAndroidTest的测试会加载HiltTestApplication,非Hilt测试使用原项目的MyApp,避免报错。
方案2:拆分测试源集,独立配置Runner
将Hilt测试与非Hilt测试拆分到不同的测试源集,分别配置对应的测试Runner:
在项目中新建
androidTestHilt测试源集,目录结构与androidTest一致:src/ androidTest/ # 非Hilt测试 androidTestHilt/ # Hilt测试 java/ res/ AndroidManifest.xml在Module的
build.gradle中配置源集与Runner:android { sourceSets { androidTestHilt { java.srcDirs = ['src/androidTestHilt/java'] res.srcDirs = ['src/androidTestHilt/res'] manifest.srcFile 'src/androidTestHilt/AndroidManifest.xml' } } defaultConfig { // 非Hilt测试使用默认Runner或自定义非Hilt Runner testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" } // 为Hilt测试源集配置自定义Runner testVariants.all { variant -> if (variant.name.contains("androidTestHilt")) { variant.instrumentationRunner = "com.yourpackage.CustomTestRunner" } } }此方案通过物理拆分测试代码,让两类测试使用各自的Runner,完全隔离配置。
注意事项
- 方案1需确保
@HiltAndroidTest注解已正确引入(依赖hilt-android-testing库) - 方案2需要维护两个测试源集,适合测试职责划分清晰的项目
内容的提问来源于stack exchange,提问作者satyajit
相关产品推荐
相关产品推荐

