Junit5+Multidex环境下Espresso测试Gradle CLI执行失败问题
I've dug into your issue where your JUnit 5-powered Espresso tests run fine in Android Studio 4 but throw errors when executed via the Gradle CLI with ./gradlew app:connectedDebugAndroidTest. The two core errors you're seeing—NoSuchMethodError for ConcurrentHashMap.newKeySet() and the missing junit-platform-runner—stem from Dex splitting behavior introduced with AGP 4.0, combined with Java 8 desugaring and MultiDex configuration gaps. Here's how to fix it step by step:
1. Force Critical JUnit 5 & Desugared Classes Into Main Dex
When AGP splits your test APK into multiple Dex files, critical initialization classes (like the JUnit 5 runner and desugared ConcurrentHashMap) might end up in non-primary Dex files, which aren't loaded early enough during instrumentation startup. To fix this:
First, add a dexOptions block to your app/build.gradle to specify a main Dex list:
android { // ... existing config dexOptions { preDexLibraries = false additionalParameters = [ '--main-dex-list', file('main-dex-list.txt').absolutePath ] } }
Then create a main-dex-list.txt file in your app module directory, and add these fully qualified class names:
de/mannodermaus/junit5/AndroidJUnit5Builder.class org/junit/platform/runner/JUnitPlatform.class org/junit/platform/commons/logging/LoggerFactory.class j$/util/concurrent/ConcurrentHashMap.class
This ensures these classes are packaged into the primary Dex file, so they're available when the instrumentation runner starts up.
2. Tweak MultiDex & Test Runner Configuration
Your CustomEspressoTestRunner already calls MultiDex.install, but we need to make sure it runs first, and that the test APK has MultiDex explicitly enabled:
Update your defaultConfig in app/build.gradle:
defaultConfig { testInstrumentationRunner "com.bonial.framework.utils.CustomEspressoTestRunner" testInstrumentationRunnerArgument "runnerBuilder", "de.mannodermaus.junit5.AndroidJUnit5Builder" multiDexEnabled true // Enable MultiDex for test APK // ... other config }
And adjust your CustomEspressoTestRunner to prioritize MultiDex installation above all other initialization logic:
@Suppress("unused") class CustomEspressoTestRunner : AndroidJUnitRunner() { override fun onCreate(arguments: Bundle?) { // Install MultiDex FIRST to ensure all Dex files are loaded early MultiDex.install(getTargetContext()) // Then apply StrictMode and call super.onCreate StrictMode.setThreadPolicy(StrictMode.ThreadPolicy.Builder().permitAll().build()) super.onCreate(arguments) } @Throws(InstantiationException::class, IllegalAccessException::class, ClassNotFoundException::class) override fun newApplication(cl: ClassLoader?, className: String?, context: Context?): Application? { return super.newApplication(cl, EspressoTestApplication::class.java.name, context) } }
3. Update Java 8 Desugaring Dependencies
AGP 4.0 has known quirks with desugaring libraries. Ensure you're using a recent desugaring dependency in your dependencies block:
dependencies { // ... existing dependencies coreLibraryDesugaring "com.android.tools:desugar_jdk_libs:1.1.5" }
This ensures all desugared JDK classes (like the missing ConcurrentHashMap method) are properly included in your test APK.
4. Clean & Rebuild to Eliminate Cached Dex Files
Old cached Dex files can cause unexpected behavior. Run these commands to start fresh:
./gradlew clean app:assembleDebugAndroidTest app:connectedDebugAndroidTest
Why This Works:
- By forcing critical classes into the main Dex, we avoid the "class not found" errors that happen when instrumentation tries to load classes from non-primary Dex files too early.
- Prioritizing MultiDex installation ensures all Dex splits are initialized before any test logic runs.
- Updating the desugaring library fixes gaps in AGP 4.0's handling of Java 8 APIs in test environments.
内容的提问来源于stack exchange,提问作者Auras

