javaandroidandroid-espressoandroidjunitrunner

Generated Android espresso test fails to run, AndroidJUnitRunner failed to resolve: Landroidx/test/platform/io/FileTestStorage;


After recording a simple espresso test on my app the test fails to run and I'm hoping someone can guide me as to why this is happening. The resulting error is:

D/AndroidJUnitRunner: Use the raw file system for managing file I/O.
E/AndroidRuntime: FATAL EXCEPTION: Instr: androidx.test.runner.AndroidJUnitRunner
    Process: com.companyname.appname, PID: 2343
    **java.lang.NoClassDefFoundError: Failed resolution of: Landroidx/test/platform/io/FileTestStorage;**
        at androidx.test.runner.AndroidJUnitRunner.registerTestStorage(AndroidJUnitRunner.java:671)
        at androidx.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:447)
        at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:2152)
     Caused by: java.lang.ClassNotFoundException: Didn't find class "androidx.test.platform.io.FileTestStorage" on path: DexPathList[[zip file "/system/framework/android.test.runner.jar", zip file "/system/framework/android.test.mock.jar", zip file "/data/app/com.companyname.appname.test-IqFAu-mtwBYt8la6Xi2kdA==/base.apk", zip file "/data/app/com.companyname.appname-mWOZlXK4F0npIJ34j66euw==/base.apk"],nativeLibraryDirectories=[/data/app/com.companyname.appname.test-IqFAu-mtwBYt8la6Xi2kdA==/lib/arm, /data/app/com.companyname.appname-mWOZlXK4F0npIJ34j66euw==/lib/arm, /system/lib, /system/product/lib, /system/vendor/lib]]
        at dalvik.system.BaseDexClassLoader.findClass(BaseDexClassLoader.java:134)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:379)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:312)
        at androidx.test.runner.AndroidJUnitRunner.registerTestStorage(AndroidJUnitRunner.java:671) 
        at androidx.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:447) 
        at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:2152) 
I/Process: Sending signal. PID: 2343 SIG: 9
Disconnected from the target VM, address: 'localhost:53625', transport: 'socket'

Build.gradle I'm using looks like:

apply plugin: 'com.android.application'
apply plugin: 'com.google.gms.google-services'

android {
    compileSdkVersion 29
    buildToolsVersion "30.0.2"
    defaultConfig {
        applicationId "com.companyname.appname"
        minSdkVersion 16
        targetSdkVersion 29
        versionCode 4
        versionName "1.3.0"
//        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        multiDexEnabled true
    }
    buildTypes {
        release {
            minifyEnabled true
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
            debuggable false
            signingConfig getSigningConfig()
            applicationVariants.all { variant ->
                variant.outputs.each { output ->
                    variant.outputs.all {
                        outputFileName = "AppName_${variant.versionName}.apk"
                    }
                }
            }
        }
        debug {
            debuggable true
            minifyEnabled false
        }
    }
    packagingOptions {
//        exclude 'META-INF/services/javax.annotation.processing.Processor'
    }
    lintOptions {
        checkReleaseBuilds false
        // Or, if you prefer, you can continue to check for errors in release builds,
        // but continue the build even when errors are found:
//        abortOnError false
    }
    dexOptions {
        preDexLibraries false
    }
}

dependencies {
    implementation fileTree(dir: 'libs', include: ['*.jar'])
    implementation 'com.google.firebase:firebase-analytics:17.2.2'
    implementation 'com.google.android.gms:play-services:8.3.0'
    implementation 'androidx.appcompat:appcompat:1.3.1'
    implementation 'androidx.lifecycle:lifecycle-extensions:2.0.0'
    implementation 'androidx.versionedparcelable:versionedparcelable:1.1.1'
    implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
    implementation 'androidx.multidex:multidex:2.0.1'
    implementation 'com.google.android.material:material:1.0.0'
    implementation 'androidx.test.ext:junit:1.1.3'

    androidTestImplementation 'androidx.test:runner:1.4.1-alpha01'
    androidTestImplementation 'androidx.test:rules:1.4.1-alpha01'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.0-alpha01'
}

Espresso java file (with some commented-out things I've tried):

package com.companyname.appname;

import androidx.test.core.app.ActivityScenario;
import androidx.test.espresso.DataInteraction;
import androidx.test.espresso.ViewInteraction;
import androidx.test.ext.junit.rules.ActivityScenarioRule;
import androidx.test.filters.LargeTest;
import androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner;
import androidx.test.rule.ActivityTestRule;
import androidx.test.runner.AndroidJUnit4;

import android.view.View;
import android.view.ViewGroup;
import android.view.ViewParent;

import static androidx.test.InstrumentationRegistry.getInstrumentation;
import static androidx.test.espresso.Espresso.onData;
import static androidx.test.espresso.Espresso.onView;
import static androidx.test.espresso.Espresso.pressBack;
import static androidx.test.espresso.Espresso.openActionBarOverflowOrOptionsMenu;
import static androidx.test.espresso.action.ViewActions.*;
import static androidx.test.espresso.assertion.ViewAssertions.*;
import static androidx.test.espresso.matcher.ViewMatchers.*;

import com.companyname.appname.R;

import org.hamcrest.Description;
import org.hamcrest.Matcher;
import org.hamcrest.TypeSafeMatcher;
import org.hamcrest.core.IsInstanceOf;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;

import static org.hamcrest.Matchers.allOf;
import static org.hamcrest.Matchers.anything;
import static org.hamcrest.Matchers.is;

@LargeTest
@RunWith(AndroidJUnit4.class) //AndroidJUnit4ClassRunner.class
public class MainActivityTestPortrait2
{

    @Rule
    public ActivityTestRule<MainActivity> mActivityTestRule = new ActivityTestRule<>(MainActivity.class);
//    public ActivityScenarioRule<MainActivity> activityRule =
//            new ActivityScenarioRule<>(MainActivity.class);

    @Test
    public void mainActivityTestPortrait2()
    {
//        ActivityScenario scenario = activityRule.getScenario();

        ViewInteraction relativeLayout = onView(
                allOf(withId(R.id.menuButton),
                        childAtPosition(
                                childAtPosition(
                                        withClassName(is("com.android.internal.widget.ActionBarView")),
                                        1),
                                2),
                        isDisplayed()));
        relativeLayout.perform(click());

        ViewInteraction relativeLayout2 = onView(
                allOf(withId(R.id.menuButton),
                        childAtPosition(
                                childAtPosition(
                                        withClassName(is("com.android.internal.widget.ActionBarView")),
                                        1),
                                2),
                        isDisplayed()));
        relativeLayout2.perform(click());

        ViewInteraction relativeLayout3 = onView(
                allOf(withId(R.id.menuButton),
                        childAtPosition(
                                childAtPosition(
                                        withClassName(is("com.android.internal.widget.ActionBarView")),
                                        1),
                                2),
                        isDisplayed()));
        relativeLayout3.perform(click());
    }

    private static Matcher<View> childAtPosition(
            final Matcher<View> parentMatcher, final int position)
    {

        return new TypeSafeMatcher<View>()
        {
            @Override
            public void describeTo(Description description)
            {
                description.appendText("Child at position " + position + " in parent ");
                parentMatcher.describeTo(description);
            }

            @Override
            public boolean matchesSafely(View view)
            {
                ViewParent parent = view.getParent();
                return parent instanceof ViewGroup && parentMatcher.matches(parent)
                        && view.equals(((ViewGroup) parent).getChildAt(position));
            }
        };
    }
}

Solution

  • First of, the dependency on extension functions should not be in base implementation

    implementation 'androidx.test.ext:junit:1.1.3'
    

    what should be there is a core library for tests:

    // activity does not start without it
    debugImplementation "androidx.test:core:1.4.0"  // or implementation "androidx.test:core:1.4.0"
    

    Second, with such bugs, try to have all the common library versions aligned. Also, the usual suspect is your case should be any -alpha library.

    So try:

    androidTestImplementation "androidx.test:runner:1.4.0"
    androidTestImplementation "androidx.test:rules:1.4.0"
    androidTestImplementation "androidx.test.espresso:espresso-core:3.4.0"
    

    and instead of alpha libraries and then go from there.