使用 ProGuard + Dagger 时 Firebase 测试实验室失败
Firebase Test Lab fails when using ProGuard + Dagger
当满足以下条件时,仪器化测试确实可以在本地模拟器和物理设备上通过,但在 Firebase 测试实验室中会失败:
- 为调试版本启用了 ProGuard;
- 同时存在 Dagger 和 Espresso 依赖项。
FTL 显示不同的测试问题:
1) 如果 APIs 26-28 它显示 Instrumentation run failed due to 'java.lang.NoClassDefFoundError'
或 Instrumentation run failed due to 'Process crashed.'
异常堆栈跟踪看起来像这样,它并不总是显示在 Firebase 中,但总是存在于 logcat:
Rejecting re-init on previously-failed class java.lang.Class<androidx.test.espresso.core.internal.deps.dagger.internal.Factory>:
java.lang.NoClassDefFoundError: Failed resolution of: Ljavax/inject/Provider;
FATAL EXCEPTION: Instr: androidx.test.runner.AndroidJUnitRunner
Process: com.example.debug, PID: 11425
java.lang.NoClassDefFoundError: Failed resolution of: Ljavax/inject/Provider;
at java.lang.Class.classForName(Native Method)
at java.lang.Class.forName(Class.java:453)
at androidx.test.internal.runner.TestLoader.doCreateRunner(TestLoader.java:72)
at androidx.test.internal.runner.TestLoader.getRunnersFor(TestLoader.java:104)
at androidx.test.internal.runner.TestRequestBuilder.build(TestRequestBuilder.java:789)
at androidx.test.runner.AndroidJUnitRunner.buildRequest(AndroidJUnitRunner.java:544)
at androidx.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:387)
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:2145)
Caused by: java.lang.ClassNotFoundException: Didn't find class "javax.inject.Provider" on path: DexPathList[[zip file "/system/framework/android.test.runner.jar", zip file "/system/framework/android.test.mock.jar", zip file "/data/app/com.example.debug.test-9kvw--JgNKzmuQurRdDbCQ==/base.apk", zip file "/data/app/com.example.debug-sz-oCUGs05zlEadCzyqsDA==/base.apk"],nativeLibraryDirectories=[/data/app/com.example.debug.test-9kvw--JgNKzmuQurRdDbCQ==/lib/arm64, /data/app/com.example.debug-sz-oCUGs05zlEadCzyqsDA==/lib/arm64, /system/lib64]]
at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:134)
at java.lang.ClassLoader.loadClass(ClassLoader.java:379)
at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
... 8 more
2) 我还在 API 21 上 运行 进行了一项测试,日志中只有一个 NoClassDefFoundError。但是,此异常也出现在 APIs 26-28,但它是上面显示的异常的一部分。也许它在不同 API 级别上的登录方式有所不同。
java.lang.NoClassDefFoundError: androidx.test.espresso.core.internal.deps.dagger.internal.Factory
FATAL EXCEPTION: Instr: androidx.test.runner.AndroidJUnitRunner
Process: com.example.debug, PID: 5691
java.lang.NoClassDefFoundError: androidx.test.espresso.core.internal.deps.dagger.internal.Factory
at java.lang.Class.classForName(Native Method)
at java.lang.Class.forName(Class.java:308)
at androidx.test.internal.runner.TestLoader.doCreateRunner(Unknown Source)
at androidx.test.internal.runner.TestLoader.getRunnersFor(Unknown Source)
at androidx.test.internal.runner.TestRequestBuilder.build(Unknown Source)
at androidx.test.runner.AndroidJUnitRunner.buildRequest(Unknown Source)
at androidx.test.runner.AndroidJUnitRunner.onStart(Unknown Source)
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1837)
build.gradle 配置中的一些相关行:
android {
defaultConfig {
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
}
buildTypes {
debug {
minifyEnabled true
useProguard true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules-debug.pro'
testProguardFile 'proguard-rules-test.pro'
}
}
}
dependencies {
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:core:1.0.0-beta01'
androidTestImplementation('androidx.test.espresso:espresso-core:3.1.0-beta01') {
// exclude module: 'javax.inject' - Exclusion doesn't help
}
// androidTestImplementation 'javax.inject:javax.inject:1' - Inclusion doesn't help either
androidTestImplementation('androidx.test.ext:junit:1.0.0-beta01') {
exclude group: "org.junit"
}
androidTestImplementation 'androidx.test:runner:1.1.0-beta01'
androidTestImplementation 'androidx.test:rules:1.1.0-beta01'
androidTestImplementation 'org.mockito:mockito-android:2.22.0'
implementation 'com.google.dagger:dagger:2.16'
kapt 'com.google.dagger:dagger-compiler:2.16'
}
proguard-rules-test.pro:
-ignorewarnings
-dontshrink
-dontoptimize
-dontobfuscate
禁用 ProGuard 或删除 Dagger 依赖项后,测试开始通过 FTL。
所以我联系了 Firebase 支持并得到了一个非常简单的解决方案。
将以下规则添加到 proguard-rules-debug.pro
-keep class javax.inject.** { *; }
目前还不清楚为什么本地测试没有出现这个问题
但至少这个解决方案有效。
当满足以下条件时,仪器化测试确实可以在本地模拟器和物理设备上通过,但在 Firebase 测试实验室中会失败:
- 为调试版本启用了 ProGuard;
- 同时存在 Dagger 和 Espresso 依赖项。
FTL 显示不同的测试问题:
1) 如果 APIs 26-28 它显示 Instrumentation run failed due to 'java.lang.NoClassDefFoundError'
或 Instrumentation run failed due to 'Process crashed.'
异常堆栈跟踪看起来像这样,它并不总是显示在 Firebase 中,但总是存在于 logcat:
Rejecting re-init on previously-failed class java.lang.Class<androidx.test.espresso.core.internal.deps.dagger.internal.Factory>:
java.lang.NoClassDefFoundError: Failed resolution of: Ljavax/inject/Provider;
FATAL EXCEPTION: Instr: androidx.test.runner.AndroidJUnitRunner
Process: com.example.debug, PID: 11425
java.lang.NoClassDefFoundError: Failed resolution of: Ljavax/inject/Provider;
at java.lang.Class.classForName(Native Method)
at java.lang.Class.forName(Class.java:453)
at androidx.test.internal.runner.TestLoader.doCreateRunner(TestLoader.java:72)
at androidx.test.internal.runner.TestLoader.getRunnersFor(TestLoader.java:104)
at androidx.test.internal.runner.TestRequestBuilder.build(TestRequestBuilder.java:789)
at androidx.test.runner.AndroidJUnitRunner.buildRequest(AndroidJUnitRunner.java:544)
at androidx.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:387)
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:2145)
Caused by: java.lang.ClassNotFoundException: Didn't find class "javax.inject.Provider" on path: DexPathList[[zip file "/system/framework/android.test.runner.jar", zip file "/system/framework/android.test.mock.jar", zip file "/data/app/com.example.debug.test-9kvw--JgNKzmuQurRdDbCQ==/base.apk", zip file "/data/app/com.example.debug-sz-oCUGs05zlEadCzyqsDA==/base.apk"],nativeLibraryDirectories=[/data/app/com.example.debug.test-9kvw--JgNKzmuQurRdDbCQ==/lib/arm64, /data/app/com.example.debug-sz-oCUGs05zlEadCzyqsDA==/lib/arm64, /system/lib64]]
at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:134)
at java.lang.ClassLoader.loadClass(ClassLoader.java:379)
at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
... 8 more
2) 我还在 API 21 上 运行 进行了一项测试,日志中只有一个 NoClassDefFoundError。但是,此异常也出现在 APIs 26-28,但它是上面显示的异常的一部分。也许它在不同 API 级别上的登录方式有所不同。
java.lang.NoClassDefFoundError: androidx.test.espresso.core.internal.deps.dagger.internal.Factory
FATAL EXCEPTION: Instr: androidx.test.runner.AndroidJUnitRunner
Process: com.example.debug, PID: 5691
java.lang.NoClassDefFoundError: androidx.test.espresso.core.internal.deps.dagger.internal.Factory
at java.lang.Class.classForName(Native Method)
at java.lang.Class.forName(Class.java:308)
at androidx.test.internal.runner.TestLoader.doCreateRunner(Unknown Source)
at androidx.test.internal.runner.TestLoader.getRunnersFor(Unknown Source)
at androidx.test.internal.runner.TestRequestBuilder.build(Unknown Source)
at androidx.test.runner.AndroidJUnitRunner.buildRequest(Unknown Source)
at androidx.test.runner.AndroidJUnitRunner.onStart(Unknown Source)
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1837)
build.gradle 配置中的一些相关行:
android {
defaultConfig {
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
}
buildTypes {
debug {
minifyEnabled true
useProguard true
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules-debug.pro'
testProguardFile 'proguard-rules-test.pro'
}
}
}
dependencies {
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test:core:1.0.0-beta01'
androidTestImplementation('androidx.test.espresso:espresso-core:3.1.0-beta01') {
// exclude module: 'javax.inject' - Exclusion doesn't help
}
// androidTestImplementation 'javax.inject:javax.inject:1' - Inclusion doesn't help either
androidTestImplementation('androidx.test.ext:junit:1.0.0-beta01') {
exclude group: "org.junit"
}
androidTestImplementation 'androidx.test:runner:1.1.0-beta01'
androidTestImplementation 'androidx.test:rules:1.1.0-beta01'
androidTestImplementation 'org.mockito:mockito-android:2.22.0'
implementation 'com.google.dagger:dagger:2.16'
kapt 'com.google.dagger:dagger-compiler:2.16'
}
proguard-rules-test.pro:
-ignorewarnings
-dontshrink
-dontoptimize
-dontobfuscate
禁用 ProGuard 或删除 Dagger 依赖项后,测试开始通过 FTL。
所以我联系了 Firebase 支持并得到了一个非常简单的解决方案。
将以下规则添加到 proguard-rules-debug.pro
-keep class javax.inject.** { *; }
目前还不清楚为什么本地测试没有出现这个问题
但至少这个解决方案有效。