AndroidX:未注册测试工具!必须在注册测试工具下运行。

91
我正在尝试运行依赖于上下文的本地单元测试,并按照以下指南进行操作:https://developer.android.com/training/testing/unit-testing/local-unit-tests#kotlin,我像这样设置了我的项目(遵循此链接: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'
}

我的espresso版本是espressoVersion = '3.1.0'

我的测试位于module-name/src/test/java/,看起来像这样:

    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) {
            }
        }
    }
}
每次我运行它都会给我一个错误信息:
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)

如果我将其作为仪器测试(更改包)运行,则不会出现错误。

但是,我认为此指南的目的是能够使用Android框架类(例如Context)运行单元测试。

我甚至尝试运行class UnitTestSample,但仍然出现相同的错误。

我还从项目中删除了所有android.support依赖项。

有任何解决方法吗?


2
在我的情况下(使用Robolectric进行单元测试):1. 将所有的androidTestImplementation更改为testImplementation 2. 在build.gradle中添加testImplementation 'org.robolectric:robolectric:4.2.1',并在测试类中添加以下注释:@RunWith(AndroidJUnit4.class) - Kirill Karmazin
1
在我的情况下,我是在“test”源集中编写instrumentaionTest,而不是“androidTest”。确保您操作正确。 - Sohail Pathan
15个回答

34

更新

如果您使用的是最新版本的gradle,则不应再遇到此错误。


我也遇到了这个问题。

如果您想迁移到Robolectric 4.0,请参考这里,建议在gradle.properties中添加以下行。

android.enableUnitTestBinaryResources=true
问题在于,如果你将此添加到gradle.properties中,它将输出以下警告:

警告:选项设置“android.enableUnitTestBinaryResources=true”是实验性的和不受支持的。

现在,如果您查看Robolectric发布这里。您会发现这是一个已知问题,在其中他们指出

Android Gradle插件可能报告以下警告,可以安全地忽略:警告:选项设置“android.enableUnitTestBinaryResources=true”是实验性的和不受支持。 Android Gradle插件3.4将解决此问题。

我认为除非您可以将gradle更新到3.4,否则您将无法解决此问题。

相反,我所做的是将Robolectric 4.0作为依赖项包含。

testImplementation "org.robolectric:robolectric:4.0.2"

并在我的测试类上注解

@RunWith(RobolectricTestRunner::class)

这应该能让你的测试正常工作。

现在当您运行测试时,您会注意到Robolectric将记录以下内容:

[Robolectric] 注意:旧资源模式已弃用;请参见 http://robolectric.org/migrating/#migrating-to-40

暂时忽略此信息,但是尽快更新gradle后,请迁移到新的Robolectric测试。


它给出了错误 "error: <identifier> expected
@RunWith(RobolectricTestRunner::class)"
- Hoàng Tùng
3
“latest gradle version”指的是哪个版本?这对于想知道他们是否需要更新或者已经使用比你所提到的版本更新的版本的人会很有帮助。 - arekolek

23

我按照官方指南操作时也遇到了这个问题,以下步骤可以解决。

在应用的build.gradle中添加testImplementation

// 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'

官方指南漏掉了两个testImplementations。

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

testImplementation 'org.robolectric:robolectric:4.4'

在应用的build.gradle文件中添加testOptions

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

@RunWith(AndroidJUnit4::class)添加到您的测试类中

示例:

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")
    }
}

注意

当您的targetSdkVersion大于29时,需要使用@Config(sdk = [Q])。因为robolectric不支持targetSdkVersion大于29


测试方法中缺少测试注释? - undefined
我导入了所有东西,但是出现了错误[error: cannot find symbol @Config(sdk = 29)],使用的是Java - undefined

16
花费数小时在类似问题上,问题不在依赖关系中,而是在AndroidStudio本身。根据答案:IDE尝试运行本地单元测试而不是仪器化测试。

Local tests icon.

确保它作为被检测的测试运行(红色是本地测试,绿色是被检测的测试):

Instrumented tests icon

为类添加仪器化测试后,它在仪器化下按预期运行。我是怎么做到的?我找到了两种方法:

1)编辑配置(如最后一张截图所示),并手动添加函数

2)在项目选项卡(左上角)中选择“Tests”而不是“android”,找到测试,右键单击-创建测试。完成此步骤后,所有新测试都将在仪器化测试下运行


12
也许我理解有误,但是这个想法不是能够在JVM上运行测试而不使用Android框架的吗? - Jonathan Persgarden

5

下面这些内容在谷歌测试指南中没有提到,但是这是我发现的:

  1. androidx.test 在单元测试中只是一个接口和API(对于仪器化测试我不确定),需要使用实现库,这就是为什么需要引入 robolectric 的依赖:testImplementation "org.robolectric:robolectric:{version}"
  2. @RunWith(AndroidJUnit4.class) 是必需的。要得到未过时的类,您需要添加:testImplementation "androidx.test.ext:junit:{version}"。顺便说一句,此依赖关系还具有传递性 junit4 倚赖。

此外,如果您使用 java 8compileSdkVersion 29 或更高版本,则可能会遇到以下问题: Failed to create a Robolectric sandbox: Android SDK 29 requires Java 9 (have Java 8)。您可以在这里找到如何处理此问题的方法。


5

我曾经也遇到过类似的错误并且为了解决它而苦苦挣扎。我的问题是我在混合使用AndroidJUnit4InstrumentationRegistryApplicationProviderAndroidJUnitRunner的版本/包。确保它们都属于同一代。以下是使其运行的类:

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

为此,我需要在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'

当然,正确的做法

testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

在我的 `build.gradle` 的 `defaultConfig` 中。

我同意Boris的观点。我花了超过12个小时来解决那个问题。我有一组使用android.support.test的工作测试仪器,我不愿改变它。当我需要测试一个服务时,似乎我必须使用androidx.test。出于绝望,我回去把android.support.test改成了androidx.test,并将方法InstrumentationRegistry.getTargetContext()更改为InstrumentationRegistry.getInstrumentation().getTargetContext(),最终那个错误消失了,其他测试仍然运行(松了一口气)。 - Brian Reinhold

2

看起来你忘记使用@RunWith(AndroidJUnit4::class)注释你的TimeExtensionsUnitTest了,参考https://github.com/android/android-test/issues/409。我可以通过在我的测试中将其注释掉来复现错误。

话虽如此,这不是你遇到错误的唯一方式。我最开始遇到这个问题是当我更新一些旧的Robolectric测试用例来使用一些AndroidX api时(http://robolectric.org/androidx_test/),包括切换到@RunWith(RobolectricTestRunner::class)以外的其他方法。在我的情况下,我尝试在我的@BeforeClass中使用上下文,使用ApplicationProvider.getApplicationContext<Context>(), 这在AndroidX中是错误的,即使在Roboletric的runner中使用appContext = RuntimeEnvironment.getApplication().applicationContextappContext也是可以的。幸运的是,我能够将逻辑移到我的@Before调用中来修复问题而没有太大的影响。

更普遍地说,我注意到有关文档并没有全面详尽地解释从非常古老的android.support.test Android测试支持库和Roboletric依赖项迁移到AndroidX的过程,但是这里还有一些其他的注意事项:
  • 如果我想在模拟器/物理设备上运行真实的仪器测试,请确保测试位于src/androidTest下。这也意味着我需要在我的build.gradle文件中将依赖项从testImplementation => androidTestImplementation更改为androidx.test库,并在defaultConfig部分明确设置testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
  • https://developer.android.com/training/testing/local-tests https://developer.android.com/training/testing/instrumented-tests
  • 如果我愿意使用Robolectric在本地运行这些测试,我可以将它们保留在src/test下,使用testImplementation声明依赖项,并且不需要testInstrumentationRunner。很好的是,我不必更改代码就可以这样做,因为我正在使用与Roboletric兼容的AndroidX Test API,版本为v4.0。

2

在我的情况下,我在一个测试包中的片段中使用了 getApplicationContext(),我只需将其更改为 getContext()。这样就解决了我的崩溃问题!


2
请确保将仪器测试(使用Runner运行的测试)放在androidTest中,而不仅仅是test。

0

[注意:记住以下内容]

AndroidJUnit4.class | 用于在名为androidTest的源集中运行仪器测试用例[需要手机或模拟器]

AndroidJUnit4ClassRunner | 用于在名为test文件夹的源集中运行本地测试用例。[不需要手机/模拟器]

异常或改进情况 | 使用Robo-electric和支持的junit4依赖项,然后可以在test文件夹中使用AndroidJUnit4.class来进行本地测试。

使用此依赖项[尝试添加最新版本]

testImplementation "org.robolectric:robolectric:4.4"

然后在您的测试类中,使用@RunWith(AndroidJUnit4::class) 例如:@RunWith(AndroidJUnit4::class)

-------供参考-----

 @RunWith(AndroidJUnit4::class)

class TasksViewModelTest {

    @Test
    fun addNewTask_setsNewTaskEvent() {

        // Given a fresh TasksViewModel
        var tasksViewModel = TasksViewModel(ApplicationProvider.getApplicationContext())

        // When adding a new task
        tasksViewModel.addNewTask()

        // Then the new task event is triggered

    }
}

0

我遇到了同样的问题,这是我如何解决它的方法:

  • 将我的测试类移动到 "androidTest" 包中
  • 使用 @RunWith(AndroidJUnit4.class) 注释测试类

希望这可以帮助到你


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接