AndroidX : No instrumentation registered! Must run under a registering instrumentation

43,401

Solution 1

Update

You should no longer encounter this error if youre using the latest gradle version.


I also encountered this issue.

If you look at migrating to Robolectric 4.0 here, it suggest to add the following line in your gradle.properties.

android.enableUnitTestBinaryResources=true

The problem is that, if you add this you your gradle.properties, it will output this warning:

WARNING: The option setting 'android.enableUnitTestBinaryResources=true' is experimental and unsupported.

Now, if you look at Robolectric releases here. You could see that this is a known issue where they state that

Android Gradle Plugin may report the following warning, which may be safely ignored: WARNING: The option setting 'android.enableUnitTestBinaryResources=true' is experimental and unsupported.. Android Gradle Plugin 3.4 will resolve this issue.

I believe unless you could update you gradle to 3.4. You won't be able to solve this issue.

What I did instead was to include Robolectric 4.0 as dependency.

testImplementation "org.robolectric:robolectric:4.0.2"

and annotate my test class with

@RunWith(RobolectricTestRunner::class)

This should make your test work.

Now when you run the test, you'll notice that Robolectric will log the following:

[Robolectric] NOTICE: legacy resources mode is deprecated; see http://robolectric.org/migrating/#migrating-to-40

Ignore this for now but as soon as you could update your gradle, migrate to the new Robolectric testing.

Solution 2

I follow the official guide also met this issue, fix it with below steps.

Add testImplementation in app build.gradle

// Required -- JUnit 4 framework
testImplementation 'junit:junit:4.13.1'

testImplementation 'androidx.test:core-ktx:1.3.0'
testImplementation 'androidx.test.ext:junit-ktx:1.1.2'

// Robolectric environment
testImplementation 'org.robolectric:robolectric:4.4'

// Optional -- truth
testImplementation 'androidx.test.ext:truth:1.3.0'
testImplementation 'com.google.truth:truth:1.0'

// Optional -- Mockito framework
testImplementation 'org.mockito:mockito-core:3.3.3'

The official guide missed two testImplementations

testImplementation 'androidx.test.ext:junit-ktx:1.1.2'

testImplementation 'org.robolectric:robolectric:4.4'

Add testOptions block in app build.gradle

 android {
        // ...
        testOptions {
            unitTests.includeAndroidResources = true
        }
    }

Add @RunWith(AndroidJUnit4::class) to your test class

Example:

import android.content.Context
import android.os.Build.VERSION_CODES.Q
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.annotation.Config

@RunWith(AndroidJUnit4::class)
@Config(sdk = [Q])
class UnitTestWithContextDemoTest {

    private val context: Context = ApplicationProvider.getApplicationContext()
    
    fun test_getPackageName() {
        assertThat(context.packageName).contains("your_package_name")
    }
}

NOTE

@Config(sdk = [Q]) is required when your targetSdkVersion greater than 29. Because robolectric NOT support targetSdkVersion greater than 29.

Solution 3

Spend hours on similar issue, and the problem wasn't in dependencies, rather in AndroidStudio itself Based on the answer:

IDE tries to run local unit tests instead of instrumented

Local tests icon.

Make sure it's run as instrumented test (red is local tests, green - instrumented):

Instrumented tests icon

After added instrumented test for the class it's run as expected under instrumented. How I done this? 2 ways I found:

1) Edit configuration (as on the last screenshot) and adding function manually

2) Under Project tap (top left corner) I selected Tests instead of android, found the test, right click - create test. After this step all new tests are run under instrumented tests

Solution 4

I had similar error and was struggling a lot to fix it. My problem was that I was mixing AndroidJUnit4, InstrumentationRegistry, ApplicationProvider and AndroidJUnitRunnerversions / packages. Make sure they all are of the same generation. These are the classes that made it all run for me:

  • androidx.test.runner.AndroidJUnitRunner
  • androidx.test.platform.app.InstrumentationRegistry
  • androidx.test.ext.junit.runners.AndroidJUnit4
  • androidx.test.core.app.ApplicationProvider

for these I needed the following in the dependencies part of my build.gradle

androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.1'
androidTestImplementation 'androidx.test:core:1.1.0'
androidTestImplementation 'androidx.test.ext:junit:1.1.0'
androidTestImplementation "com.android.support:support-annotations:27.1.1"
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test:rules:1.0.2'

And of course the correct

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

in my defaultConfig of the build.gradle

Solution 5

Next things are not mentioned on google test guide, but they are what I found:

  1. androidx.test in case of unit tests is just an interface/api (I don't know what about instrumented tests) and it needs implementations, which is robolectric library. That's why robolectric dependency is also required: testImplementation "org.robolectric:robolectric:{version}"
  2. @RunWith(AndroidJUnit4.class) is required. To get nondeprecated class you need to add: testImplementation "androidx.test.ext:junit:{version}". By the way this dependency has transitive junit4 dependensy.

Also you can faced with: Failed to create a Robolectric sandbox: Android SDK 29 requires Java 9 (have Java 8) in case you use java 8 and compileSdkVersion 29 or above. Here you can find how to deal with it.

Share:
43,401
julioribeiro
Author by

julioribeiro

Updated on July 05, 2022

Comments

  • julioribeiro
    julioribeiro almost 2 years

    I'm trying to run a local unit test that depends on the context, and was following this guide: https://developer.android.com/training/testing/unit-testing/local-unit-tests#kotlin and I set up my project like this (following this link : https://developer.android.com/training/testing/set-up-project ):

    build.gradle(app)

    android {
    compileSdkVersion 28
    buildToolsVersion '27.0.3'
    defaultConfig {
        minSdkVersion 21
        targetSdkVersion 27
        versionCode 76
        versionName "2.6.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
        multiDexEnabled true
    
    useLibrary 'android.test.runner'
        useLibrary 'android.test.base'
        useLibrary 'android.test.mock'
    
    }
    testOptions {
        unitTests.returnDefaultValues = true
        unitTests.all {
            // All the usual Gradle options.
            testLogging {
                events "passed", "skipped", "failed", "standardOut", "standardError"
                outputs.upToDateWhen { false }
                showStandardStreams = true
            }
        }
        unitTests.includeAndroidResources = true
    
    }
    dependencies {
    implementation fileTree(include: ['*.jar'], dir: 'libs')
    
    androidTestImplementation("androidx.test.espresso:espresso-core:$espressoVersion", {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    // Espresso UI Testing dependencies
    implementation "androidx.test.espresso:espresso-idling-resource:$espressoVersion"
    androidTestImplementation "androidx.test.espresso:espresso-contrib:$espressoVersion"
    androidTestImplementation "androidx.test.espresso:espresso-intents:$espressoVersion"
    
    testImplementation 'androidx.test:core:1.0.0'
    
    // AndroidJUnitRunner and JUnit Rules
    androidTestImplementation 'androidx.test:runner:1.1.0'
    androidTestImplementation 'androidx.test:rules:1.1.0'
    // Espresso Assertions
    androidTestImplementation 'androidx.test.ext:junit:1.0.0'
    androidTestImplementation 'androidx.test.ext:truth:1.0.0'
    androidTestImplementation 'com.google.truth:truth:0.42'
        implementation 'androidx.multidex:multidex:2.0.0'
    }
    

    My espresso_version is espressoVersion = '3.1.0'

    My test that is located in module-name/src/test/java/ looks like this:

        import android.content.Context
    import androidx.test.core.app.ApplicationProvider
    import com.instacart.library.truetime.TrueTime
    import edu.mira.aula.shared.extensions.android.trueDateNow
    import edu.mira.aula.shared.network.ConnectivityHelper
    import kotlinx.coroutines.experimental.runBlocking
    import org.junit.Assert
    import org.junit.Before
    import org.junit.Test
    import java.util.*
    import java.util.concurrent.CountDownLatch
    
    class TimeExtensionsUnitTest {
    private lateinit var instrumentationCtx: Context
    
    @Before
    fun setup() {
        instrumentationCtx = ApplicationProvider.getApplicationContext<Context>()
    }
     @Test
    fun testTrueTimeValueReturnsIfInitialized() {
        if (ConnectivityHelper.isOnline(instrumentationCtx)) {
            runBlocking {
                val countDownLatch = CountDownLatch(1)
                TrueTime.build()
                        .withSharedPreferencesCache(instrumentationCtx)
                        .withConnectionTimeout(10000)
                        .initialize()
                countDownLatch.countDown()
    
                try {
                    countDownLatch.await()
                    val dateFromTrueTime = trueDateNow()
                    val normalDate = Date()
                    Assert.assertNotEquals(dateFromTrueTime, normalDate)
                } catch (e: InterruptedException) {
                }
            }
        }
    }
    

    Everytime I run it, it gives me:

    java.lang.IllegalStateException: No instrumentation registered! Must run under a registering instrumentation.
     at androidx.test.platform.app.InstrumentationRegistry.getInstrumentation(InstrumentationRegistry.java:45)
      at androidx.test.core.app.ApplicationProvider.getApplicationContext(ApplicationProvider.java:41)
    

    If I run it as a Instrumental Test(changing the package) it runs without errors. But I thought that this guide was exactly to be able to run unit test using Android Framework classes such as Context. I even tried run that class UnitTestSample but the same error occurs.

    I also removed all android.support dependencies from my project

    Any ideas on how to solve it?

  • Jeremy Harris
    Jeremy Harris over 5 years
    While this may be an answer, it is good practice to add more details to your answer to help OP and future readers. Code only answers are generally discouraged.
  • Brian Reinhold
    Brian Reinhold almost 5 years
    I would agree with Boris. I spent more than 12 hours trying to resolve that problem. I had a set of working instrumented tests using the android.support.test and I was hesitant to change that. When I needed to test a service, it seemed I had to go with androidx,test. Out of desperation I went back and changed android.support.test to androidx.test and the method InstrumentationRegistry.getTargetContext() to InstrumentationRegistry.getInstrumentation().getTargetContex‌​t() and FINALLY that error went away and the other tests still ran (sigh of relief).
  • Jonathan Persgarden
    Jonathan Persgarden almost 4 years
    Maybe I understand this incorrectly. But isn't the idea to be able to run the tests on the JVM without using the Android framework?
  • Hoàng Tùng
    Hoàng Tùng over 3 years
    It gives the error "error: <identifier> expected @RunWith(RobolectricTestRunner::class)"
  • arekolek
    arekolek over 2 years
    What version do you mean by the latest gradle version? Would be helpful for anybody wondering if they actually need to update or already use a version newer than what you referred to