android-test
android-test copied to clipboard
Unresolved hamcrest Matchers when updating espresso to v3.4.0
Description
After updating my espresso dependency from v3.3.0 to v3.4.0 my project complains that it can't find hamcrest Matchers.
I'm using the following espresso dependencies:
private const val version = "3.4.0"
const val core = "androidx.test.espresso:espresso-core:$version"
const val contrib = "androidx.test.espresso:espresso-contrib:$version"
const val intents = "androidx.test.espresso:espresso-intents:$version"
const val accessibility = "androidx.test.espresso:espresso-accessibility:$version"
const val web = "androidx.test.espresso:espresso-web:$version"
And I'm adding these in my project using androidTestImplementation
Expected Results
The test compiles and I can run instrumentation tests
Actual Results
I get a bunch of Unresolved reference errors
Unresolved reference: equalTo
Unresolved reference: Matchers
Unresolved reference: allOf
Unresolved reference: is
.
.
.
The same configuration works fine if I use v3.3.0
It also works if I explicitly add org.hamcrest:hamcrest:2.2 dependency
I was able to workaround this isssue by downgrading espresso-contrib and espresso-accessibility to v3.3.0. as mentioned here https://stackoverflow.com/questions/66915068/test-error-noclassdeffounderror-failed-resolution-of-lorg-hamcrest-matchers
https://github.com/AdevintaSpain/Barista/issues/357#issuecomment-1076357823 has the context why it breaks.
TL;DR espresso-contrib 3.4.0 pulls in accessibility-test-framework 3.1, which pulls in hamcrest library & core 2.2 and breaks all the references.
Note, androidx also hit this issue when working around it. The fix we did is to include accessibility-test-framework with strictly version 2.1 in any project that pulls in espresso-contrib. This bug makes espresso-contrib unusable out of the box without this workaround.
Can one of you post a repro sample? I'm confused because our tests don't have this problem
Closing due to lack of repro steps. Please reopen if you all are still hitting this
Here is a minimum project setup that repros the problem. (JDK 17+) issue-1352-repro.tar.gz
The root cause is that Hamcrest 2.2 is not binary compatible with 1.3. Several overloads were removed, like CoreMatchers.allOf(Matcher first, Matcher second).
That means the problem is triggered when one compilation unit uses methods from Hamcrest 1.3 that were removed in Hamcrest 2.2, another compilation unit uses methods from Hamcrest 2.2 that were not in Hamcrest 1.3, and a third compilation unit depends on the other two. Everything will compile just fine, but it will crash on execution (assuming the problematic code is actually called).
In the repro this happens because lib-a depends on espresso-core (pulling in hamcrest 1.3), lib-b depends on espresso-contrib (pulling in 2.2), and app depends on lib-a and lib-b.
While this problem will always be around as long as libraries keep using both versions of hamcrest, I think we can do some things to mitigate:
- only depend on a single version of hamcrest throughout our libraries
- avoid methods that are only in one of the two versions, so users can force use the version that suits them
- ask hamcrest to restore binary compatibility and do a 2.2.1 bug fix release
Thanks for the investigation Jelle!
The "only depend on a single version of hamcrest throughout our libraries" is my preferred solution. The hamcrest 2.2 dependency comes from com.google.android.apps.common.testing.accessibility.framework. I've asked them before if this could be downgraded to 1.3 and they sounded receptive. I'll follow up.
The other workaround in the works is to sever the espresso-contrib -> com.google.android.apps.common.testing.accessibility.framework dependency, but that requires versioning each espresso library independently + a major version bump of espresso.contrib so it is a little ways away due to lack of bandwidth