uses-library com.android.nfc_extras breaks AndroidTest for api 26 and above when testing on a real device
Asked Answered
W

1

7

I've suddenly figured out that this declaration:

    <uses-library
        android:name="com.android.nfc_extras"
        android:required="false"/>

inside <application> scope of my AndroidManifest.xml makes instrumentation tests to fail:

java.lang.NoSuchMethodError: No static method allOf(Lorg/hamcrest/Matcher;Lorg/hamcrest/Matcher;)Lorg/hamcrest/Matcher; in class Lorg/hamcrest/core/AllOf; or its super classes (declaration of 'org.hamcrest.core.AllOf' appears in /system/framework/com.android.nfc_extras.jar)
at org.hamcrest.Matchers.allOf(Matchers.java:33)
at android.support.test.espresso.Espresso.<clinit>(Espresso.java:187)
at android.support.test.espresso.Espresso.onView(Espresso.java:75)
at com.example.abusik.espressotest.InstrumentedTest.changeText_sameActivity(InstrumentedTest.kt:34)
at java.lang.reflect.Method.invoke(Native Method)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)

What I came up with for now:

  • Created a demo repository for you to be able to reproduce the problem quickly;
  • Only a real devices with API >= 26 are affected (e.g. Samsung SM-G935F, Huawei P20 lite);
  • Test passes on emulators with any API I have tried;
  • Test passes on real devices with API < 26;
  • Looks like missing class (and all his static methods) are included into AndroidTest apk, but at runtime Android tries to get this class from com.android.nfc_extras.jar???;
  • This behaviour may depend on NFC-feature of your phone;
  • It doesn't looks like MultiDex or obfuscation problem for me - the demo repository is not obfuscated and single-dex.

Apk analyze screenshot


I would like to know if anybody faced this problem, why is this happening and how can I keep my AndroidTests working and still use this library?


My InstrumentedTest.kt file:

package com.example.abusik.espressotest

import android.support.test.espresso.Espresso.onView
import android.support.test.espresso.action.ViewActions.*
import android.support.test.espresso.assertion.ViewAssertions.matches
import android.support.test.espresso.matcher.ViewMatchers.withId
import android.support.test.espresso.matcher.ViewMatchers.withText
import android.support.test.filters.LargeTest
import android.support.test.rule.ActivityTestRule
import android.support.test.runner.AndroidJUnit4
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
@LargeTest
class InstrumentedTest {

    private lateinit var stringToBetyped: String

    @get:Rule
    var activityRule: ActivityTestRule<MainActivity> = ActivityTestRule(MainActivity::class.java)

    @Before
    fun initValidString() {
        // Specify a valid string.
        stringToBetyped = "Espresso"
    }

    @Test
    fun changeText_sameActivity() {
        // Type text and then press the button.
        onView(withId(R.id.et)) //EXCEPTION THROWN HERE
            .perform(typeText(stringToBetyped), closeSoftKeyboard())
        onView(withId(R.id.btn)).perform(click())

        // Check that the text was changed.
        onView(withId(R.id.et))
            .check(matches(withText(stringToBetyped)))
    }
}

Test log:

Testing started at 0:09 ...

12/17 00:09:32: Launching InstrumentedTest
$ adb push /Users/a.busik/EspressoTest/app/build/outputs/apk/debug/app-debug.apk /data/local/tmp/com.example.abusik.espressotest
$ adb shell pm install -t -r "/data/local/tmp/com.example.abusik.espressotest"
Success
APK installed in 3 s 235 ms
$ adb push /Users/a.busik/EspressoTest/app/build/outputs/apk/androidTest/debug/app-debug-androidTest.apk /data/local/tmp/com.example.abusik.espressotest.test
$ adb shell pm install -t -r "/data/local/tmp/com.example.abusik.espressotest.test"
Success
APK installed in 2 s 684 ms
Running tests

$ adb shell am instrument -w -r   -e debug false -e class 'com.example.abusik.espressotest.InstrumentedTest' com.example.abusik.espressotest.test/android.support.test.runner.AndroidJUnitRunner
Client not ready yet..
Started running tests

java.lang.NoSuchMethodError: No static method allOf(Lorg/hamcrest/Matcher;Lorg/hamcrest/Matcher;)Lorg/hamcrest/Matcher; in class Lorg/hamcrest/core/AllOf; or its super classes (declaration of 'org.hamcrest.core.AllOf' appears in /system/framework/com.android.nfc_extras.jar)
at org.hamcrest.Matchers.allOf(Matchers.java:33)
at android.support.test.espresso.Espresso.<clinit>(Espresso.java:187)
at android.support.test.espresso.Espresso.onView(Espresso.java:75)
at com.example.abusik.espressotest.InstrumentedTest.changeText_sameActivity(InstrumentedTest.kt:34)
at java.lang.reflect.Method.invoke(Native Method)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at android.support.test.internal.runner.junit4.statement.RunBefores.evaluate(RunBefores.java:80)
at android.support.test.rule.ActivityTestRule$ActivityStatement.evaluate(ActivityTestRule.java:527)
at org.junit.rules.RunRules.evaluate(RunRules.java:20)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:68)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.-wrap0(Unknown Source:0)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at android.support.test.runner.AndroidJUnit4.run(AndroidJUnit4.java:101)
at org.junit.runners.Suite.runChild(Suite.java:128)
at org.junit.runners.Suite.runChild(Suite.java:126)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.-wrap0(Unknown Source:0)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at org.junit.runner.JUnitCore.run(JUnitCore.java:115)
at android.support.test.internal.runner.TestExecutor.execute(TestExecutor.java:56)
at android.support.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:384)
at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:2106)

Tests ran to completion.

I was able to find an nfc_extras.jar and it doesn't seem to contain any reference for org.hamcrest.*

nfc_extras.jar source code overview

Winger answered 16/12, 2018 at 21:33 Comment(3)
Do you uknow if the affected device is rooted or not?Hyperion
I would suggest that the expresso.core, like the Mockito library, is using the org.hamcrest.Matchers library which should be included in the com.android.nfc_extras.jar file. Although I have not personally experience this exact error in the expresso lib, I've quite often encountered the "java.lang.NoSuchMethodError: No static method" error mostly from within the Android Support libraries, which have quite often omitted certain classes. Can you please share with us the part of the gradle build file where you are declaring your expresso dependency so I can see how you declare it?Hyperion
@Mat, i'm sorry for the late answer. The affected devices I was able to reproduce the problem on are not rooted.You can find any files you are interested in in the repo: github.com/and291/…Winger
H
4

unable to reproduce on a physical MotoX4 running Android 8.0.0.

a) com.android.nfc_extras.jar might have another version of org.hamcrest.Matcher than the test application - which could theoretically be excluded, when loading it from the libs directory. that the emulator does not care might come from, that there neither is BT nor NFC available.

the main/Manifest.xml also lacks the NFC permission; adding it removes the complaint:

<uses-permission android:name="android.permission.NFC" />

b) one could even get rid of the nfc_extras.jar altogether with an androidTest/Manifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="com.example.abusik.espressotest">
    <application>
        <uses-library
            android:name="com.android.nfc_extras"
            android:required="false"
            tools:node="remove"/>
    </application>
</manifest>
Hughett answered 19/12, 2018 at 4:33 Comment(1)
Thank's for your answer, Martin! I was able to find an nfc_extras.jar and it doesn't seem to contain any reference for org.hamcrest.* I've updated my question with one more screenshot. The reproducing of the problem doesn't depends on declaration of NFC permission. Simple declaring uses-library com.android.nfc_extras in manifest somehow forces android tests to search org.hamcrest.core.AllOf or his parents or his static methods inside nfc_extras.jar. Can someone explain what's going on here!? %)Winger

© 2022 - 2024 — McMap. All rights reserved.