android / android/android-test

espresso-contrib makes ActivityScenarioRule trigger ClassNotFoundException

Open
#1,118 4 comments 0 reactions 0 assignees View on GitHub
Dominant language
Java
Stars
1.2k
Forks
342
Avg merge
11h 29m
Merged PRs (30d)
2

Description

### Description

If `espresso-contrib` is added to `build.gradle`, then adding an `ActivityScenarioRule` to a simple androidTest causes a fatal ClassNotFoundException.

### Steps to Reproduce

1. Start with a simple Android Studio project. I used the "Blank Activity" template with kotlin and SDK 27.
2. Add to `build.gradle`:
`androidTestImplementation 'androidx.test.espresso:espresso-contrib:3.4.0'`
3. Add a new member variable to an androidTest, e.g. `ExampleInstrumentedTest`:
```
@get:Rule
val rule = ActivityScenarioRule(MainActivity::class.java)
```
4. Launch an AVD (I used Android 11.0 (Google APIs) on Pixel 5)
5. Run the test

### Expected Results

The test should pass.

### Actual Results

The test hangs and eventually terminates. Immediately after the test starts, logcat reports a crash:

```
2021-09-25 02:19:35.656 10153-10153/? E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.foo.ruletest.test, PID: 10153
java.lang.NoClassDefFoundError: Failed resolution of: Landroidx/test/internal/util/Checks;
at androidx.test.core.app.InstrumentationActivityInvoker$BootstrapActivity.onResume(InstrumentationActivityInvoker.java:169)
at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1456)
at android.app.Activity.performResume(Activity.java:8135)
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:4434)
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:4476)
at android.app.servertransaction.ResumeActivityItem.execute(ResumeActivityItem.java:52)
at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:176)
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:223)
at android.app.ActivityThread.main(ActivityThread.java:7656)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
Caused by: java.lang.ClassNotFoundException: Didn't find class "androidx.test.internal.util.Checks" on path: DexPathList[[zip file "/data/app/~~dPOmzOwzgsQWBjEGt2CgBA==/com.foo.ruletest.test-3LocvMQ2WLgtGbjdq_FpWA==/base.apk"],nativeLibraryDirectories=[/data/app/~~dPOmzOwzgsQWBjEGt2CgBA==/com.foo.ruletest.test-3LocvMQ2WLgtGbjdq_FpWA==/lib/x86_64, /system/lib64, /system_ext/lib64]]
at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:207)
at java.lang.ClassLoader.loadClass(ClassLoader.java:379)
at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
at androidx.test.core.app.InstrumentationActivityInvoker$BootstrapActivity.onResume(InstrumentationActivityInvoker.java:169) 
at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1456) 
at android.app.Activity.performResume(Activity.java:8135) 
at android.app.ActivityThread.performResumeActivity(ActivityThread.java:4434) 
at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:4476) 
at android.app.servertransaction.ResumeActivityItem.execute(ResumeActivityItem.java:52) 
at android.app.servertransaction.TransactionExecutor.executeLifecycleState(TransactionExecutor.java:176) 
at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:97) 
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2066) 
at android.os.Handler.dispatchMessage(Handler.java:106) 
at android.os.Looper.loop(Looper.java:223) 
at android.app.ActivityThread.main(ActivityThread.java:7656) 
at java.lang.reflect.Method.invoke(Native Method) 
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:592) 
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:947)
```

### AndroidX Test and Android OS Versions

```
androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
androidTestImplementation 'androidx.test.ext:junit:1.1.3'
testImplementation 'junit:junit:4.13.2'
implementation 'androidx.test.espresso:espresso-contrib:3.4.0'
```

Android 11.0 (Google APIs) on virtual Pixel 5

### Other

This doesn't seem to repro if espresso-contrib is used as `androidTestImplementation` instead of as `implementation`. But a number of examples I've found use it as `implementation`.

I ran into this while trying to test `SettingsFragment`. I found a few similar (unsolved) reports:
* #964
* [Jetpack compose, Instrumental tests: java.lang.ClassNotFoundException: Didn't find class "androidx.test.internal.util.Checks"](https://stackoverflow.com/questions/68800881/jetpack-compose-instrumental-tests-java-lang-classnotfoundexception-didnt-fi)

Contributor guide

Open the contributing guide

Research direction

Start with the dependency declarations in build.gradle and the ExampleInstrumentedTest member using ActivityScenarioRule. Reproduce the failure on the stated Android 11 AVD and inspect logcat for the missing androidx.test.internal.util.Checks class. Done means the espresso-contrib setup no longer causes the ClassNotFoundException and the instrumentation test passes.

Written by the indexing model from the issue text.

Assessment

Tech stack
android, java, kotlin
Domain
mobile, testing
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.