将Junit4测试迁移到androidx:导致“delegate runner could not be loaded”的原因是什么?

62

我正在将应用程序迁移到AndroidX,但是我的单元测试似乎无法正常工作。我参考了谷歌的AndroidJunitRunnerSample示例,该示例已更新为使用新的AndroidX API。但在运行测试时,我收到以下错误:

java.lang.Exception: Delegate runner 'androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner' for AndroidJUnit4 could not be loaded. Check your build configuration.

这是我的模块build.gradle文件:

android {
    defaultConfig {
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }
}
dependencies {
    // Test dependencies
    androidTestImplementation 'androidx.test:core:1.0.0-beta02'
    androidTestImplementation 'androidx.test.ext:junit:1.0.0-beta02'
    androidTestImplementation 'androidx.test:runner:1.1.0-beta02'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0-beta02'
    androidTestImplementation "androidx.arch.core:core-testing:2.0.0"
    androidTestImplementation 'androidx.room:room-testing:2.1.0-alpha01'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0-beta02'
    androidTestImplementation 'org.hamcrest:hamcrest-library:1.3'
}

这是我的测试结构:

import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;

import androidx.test.ext.junit.runners.AndroidJUnit4;

@RunWith(AndroidJUnit4.class)
public class EntityParcelTest {

    @BeforeClass
    public void createEntities() {
        // Setup...
    }

    @Test
    void someTest() {
        // Testing here
    }

我做错了什么?


请参考以下帖子 https://dev59.com/mlMI5IYBdhLWcg3wuN-O#64478059 - Tarun A
21个回答

64

从测试类中删除@RunWith(AndroidJUnit4.class)注释解决了这个问题,虽然我无法确定为什么或者如何解决这个问题。

编辑:好的,我进行了更多的测试。我将我的应用程序迁移到Kotlin,突然间我发现测试也可以使用@RunWith注释了。以下是我发现的:

import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;

import androidx.test.ext.junit.runners.AndroidJUnit4;

@RunWith(AndroidJUnit4.class) // <-- @RunWith + @BeforeClass = Error
public class AndroidXJunitTestJava {

    @BeforeClass
    public static void setup() {
        // Setting up once before all tests
    }

    @Test
    public void testing() {
        // Testing....
    }
}

这个Java测试失败,出现了Delegate runner for AndroidJunit4 could not be loaded的错误。 但是如果我删除@RunWith注释,它就可以工作。此外,如果我只是将@BeforeClass设置替换为@Before,像这样:

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

import androidx.test.ext.junit.runners.AndroidJUnit4;

@RunWith(AndroidJUnit4.class) // <-- @RunWith + @Before = works?
public class AndroidXJunitTestJava {

    @Before
    public void setup() {
        // Setting up before every test
    }

    @Test
    public void testing() {
        // Testing....
    }
}

测试将无错误运行。我需要使用@BeforeClass注释,所以我只是移除了@RunWith

但现在我正在使用Kotlin,下面的代码(应该等同于第一个Java示例)可以工作:

import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.BeforeClass
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
class AndroidXJunitTest {

    companion object {
        @BeforeClass fun setup() {
            // Setting up
        }
    }

    @Test
    fun testing() {
        // Testing...
    }

}

同时,正如Alessandro Biessek在回答中所说,以及@Ioane Sharvadze在评论中提到的那样,@Rule注释也可能导致相同的错误。如果我添加一行代码

 @Rule val instantTaskExecutorRule = InstantTaskExecutorRule()

对于Kotlin示例,同样会出现委托运行时错误。这必须被替换为

@get:Rule val instantTaskExecutorRule = InstantTaskExecutorRule()

这里解释


但现在,测试是JUnit测试。 - Ioane Sharvadze
13
对我来说问题在于我使用了 @Rule 而不是 @get:Rule 注解来定义 ActivityTestRule。如果你正在使用 Kotlin,那么它可能会对你有所帮助。 - Ioane Sharvadze
在 Kotlin 中,对我来说,将 @Rule 替换为 @get:Rule 就足够了。它可以与 @Before 一起使用。 - Miloš Černilovský
1
对我来说,解决方案是将使用@BeforeClass注释的方法更改为静态方法,如https://dev59.com/23RB5IYBdhLWcg3wEDul#733042所述。看起来这也可能有助于解决原始问题。 - Michael Osofsky
1
在 Kotlin 中,将 @Rule 替换为 @get:Rule 对我有用。谢谢 :) - Mohit Atray
谢谢,删除 @RunWith(AndroidJUnit4.class) 后问题解决了。我通常喜欢有解释,但似乎找不到。根据文档,注释是必需的并且应该有效 https://developer.android.com/training/testing/junit-runner 我在这里推测,但似乎是某些库/类不兼容。希望有时间的人可以调查一下,如果我发现了什么,我会去做。但目前这个解决方案可行,所以我会点赞它。 - MG Developer

52

如果您在Kotlin中使用测试规则并以Java风格编写,则也会收到错误消息。

@Rule
var mainActivityActivityTestRule = ActivityTestRule(MainActivity::class.java)

你必须将 @Rule 更改为 @get:Rule

@get:Rule
var mainActivityActivityTestRule = ActivityTestRule(MainActivity::class.java) 

1
有什么区别吗? - IgorGanapolsky
3
使用 @get: 注解时,它会应用于基础 Java getter 方法上,而不是字段本身。该getter方法是为该字段创建的。 - Filipkowicz
2
好观点。我更喜欢使用@JvmField而不是@get:注解前缀,因为它生成与最初提到的语法相同的字节码,就像Java一样。我不会说这是个人偏好(因为它执行不同的操作),但在数百次测试中它已经被证明是无误的,而且我更喜欢它,因为我可以验证它是否正常工作。 - milosmns

11

当我删除@Test方法时,显示的错误消息。

您可以尝试添加一个@Test方法并运行。

@Test
public void signInTest() {


}

很奇怪,这对我来说也是一样的。一旦我添加了一个带有@Test标记的空函数,一切都好了。 - Ivan Wooll

7

在测试活动时,请确保ActivityTestRule变量为public:

@Rule
public ActivityTestRule<YourActivity> activityTestRule = new ActivityTestRule<>(YourActivity.class); 

5

以下有2种解决此问题的方法:

解决方案1:

Build --> 清除项目。然后 Build --> 重建项目

解决方案2:

有2个包含 AndroidJUnit4 的软件包:

  1. androidx.test.runner (已过时)
  2. androidx.test.ext.junit.runners

请确保您的 build.gradle (app) 文件中有这行代码

android {
    defaultConfig {
    ....
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    ....
    }
}

在测试类之前,请确保您使用已过时的(1)而不是新的但尚未稳定的(2)来运行@RunWith(AndroidJUnit4.class)


2
尽管遵循官方文档,但我花了大约2个小时才最终设置好一个AndroidJUnitTest。正如在我的测试类中所述,我更改了导入: 使用:import androidx.test.runner.AndroidJUnit4(虽然已弃用) 不要使用:import androidx.test.ext.junit.runners.AndroidJUnit4。 这不是完美的解决方案。但与浪费更多时间来运行单个测试相比,最好使用一个已弃用的类。 感谢您的回答。 - ice_chrysler

2

测试框架提供的信息太少了。我也遇到了同样的问题,并深入查看了堆栈跟踪,找到了以下验证:

enter image description here

所以您必须将@BeforeClass方法声明为static


2

Changing

@Test
void someTest() {
    // Testing here
}

to

@Test
public void someTest() {
    // Testing here
}

最初的回答。这对我有效。

2

AndroidJUnit4不支持在函数中使用@Test注解,无论是在类中还是在超类中:

  • 参数:@Test fun dontWork(param: String) {}
  • 私有访问修饰符:@Test private fun dontWork2() {}

注意:上述情况如果没有@Test注解则是允许的。


一个预期的方法可能是:

ClassTest.kt

import androidx.test.ext.junit.runners.AndroidJUnit4
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
class ClassTest : SuperTest() {

    @Test
    fun test() {}

    private fun allowedWithoutAnnotation(paramAllowed: String) {}

}

build.gradle (:mobile)

defaultConfig {
    ...
    testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}


dependencies {
    ...
    testImplementation 'junit:junit:4.12'
    androidTestImplementation 'androidx.test.ext:junit:1.1.1'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
    androidTestImplementation 'androidx.arch.core:core-testing:2.1.0'
} 

GL

2

您需要确保任何使用@BeforeClass注释标记的类均为public static。例如:

import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.runner.RunWith;

import androidx.test.ext.junit.runners.AndroidJUnit4;

@RunWith(AndroidJUnit4.class)
public class EntityParcelTest {

    @BeforeClass
    public static void createEntities() {
        // Setup...
    }

    @Test
    public void someTest() {
        // Testing here
    }

1
在我的情况下,我跳过了使用@Test进行注释测试用例的步骤。但这并不适用于你的情况。这个答案是为像我这样的其他人准备的。

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