将Junit4测试迁移到androidx:是什么原因导致“无法加载委托人”?

时间:2018-10-18 11:42:00

标签: android junit junit4 androidx

我正在将应用程序迁移到androidx,但似乎无法使单元测试正常工作。我以Google's 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
    }

我在做什么错了?

19 个答案:

答案 0 :(得分:22)

从测试类中删除@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()

说明here

答案 1 :(得分:10)

如果您在Kotlin中使用测试规则并将其编写为Java样式,也会收到错误消息

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

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

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

答案 2 :(得分:1)

您需要确保所有带有 @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
    }

答案 3 :(得分:1)

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

您可以尝试放置@Test方法并运行

@Test
public void signInTest() {


}

答案 4 :(得分:1)

在测试活动时,请确保ActivityTestRule变量是公共的:

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

答案 5 :(得分:1)

有两种方法可以尝试解决此问题:

解决方案1:

构建->清理项目。然后构建->重建项目

解决方案2:

有2个具有AndroidJUnit4的软件包

  1. androidx.test.runner(已弃用)
  2. androidx.test.ext.junit.runners

确保您的build.gradle(应用程序)具有此行

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

并确保在测试课程之前的@RunWith(AndroidJUnit4.class)中使用(1)(已弃用)而不是(2)(新的但尚未稳定)。

答案 6 :(得分:0)

就我而言,我跳过了用@Test进行注释的测试用例。这不是你的情况。这个答案是给像我这样的人的。

答案 7 :(得分:0)

也许您尚未在gradle配置文件上更新跑步者?

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

此外,AndroidStudio 3.2还提供了一个选项,可以自动将依赖项迁移到AndroidX(重构->迁移到AndroidX ...),这对我来说是有效的。

答案 8 :(得分:0)

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

答案 9 :(得分:0)

对于我来说,我通过将所有@Test@Before@After方法都声明为public并声明@BeforeClass和{{ 1}}为@AfterClass

如果您将这些方法中的任何一个保留为隐式/显式public static或显式protected;您将遇到以下异常

private

所以,正确的方法是使用

java.lang.RuntimeException: Delegate runner 'androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner' for AndroidJUnit4 could not be loaded.

代替:

@Before
public void setUp() {

}

@BeforeClass
public static void init() {

}

答案 10 :(得分:0)

就我而言,定义函数参数是问题所在。

@Test
fun foo(string: String = "") {  // Causes "Delegate runner could not be loaded" error.
    // ...
}

我必须做类似以下的事情。

@Test
fun foo() {
    foo("")
}

fun foo(string: String) {  // Can be called from other test functions.
    // ...
}

答案 11 :(得分:0)

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

enter image description here

因此您必须声明@BeforeClass方法static

答案 12 :(得分:0)

其他一些可能的原因:

  • 仅具有@SmallTest(或中/大)测试方法。用@Test标记至少一种方法可以解决问题。
  • setup() / teardown()方法不是公开的。

答案 13 :(得分:0)

我使用以下配置进行了修复:

我的依赖项:

/*Instrumentation Test*/
androidTestImplementation "org.assertj:assertj-core:3.12.2"
androidTestImplementation ('androidx.test.espresso:espresso-core:3.2.0',{
    exclude group: 'com.android.support', module: 'support-annotations'
})
androidTestImplementation "androidx.arch.core:core-testing:2.1.0-rc01"

在我的defaultConfig部分,我有:

defaultConfig {
    applicationId "uy.edu.ude.archcomponents"
    minSdkVersion 22
    targetSdkVersion 28
    versionCode 1
    versionName "1.0"
    testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"

    testInstrumentationRunnerArguments clearPackageData: 'true'
}

在测试中,我有:

package uy.edu.ude.archcomponents.repository

import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import androidx.room.Room
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.runner.AndroidJUnit4
import com.example.android.roomwordssample.WordDao
import com.example.android.roomwordssample.WordRoomDatabase
import kotlinx.coroutines.runBlocking
import org.assertj.core.api.Assertions.assertThat
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import uy.edu.ude.archcomponents.entity.Word
import java.io.IOException


@RunWith(AndroidJUnit4::class)
class WordDaoTest {

    @get:Rule
    val instantTaskExecutorRule = InstantTaskExecutorRule()

    private lateinit var wordDao: WordDao
    private lateinit var db: WordRoomDatabase

    @Before
    fun createDb() {
        val context = InstrumentationRegistry.getInstrumentation().context
        // Using an in-memory database because the information stored here disappears when the
        // process is killed.
        db = Room.inMemoryDatabaseBuilder(context, WordRoomDatabase::class.java)
                // Allowing main thread queries, just for testing.
                .allowMainThreadQueries()
                .build()
        wordDao = db.wordDao()
    }

    @After
    @Throws(IOException::class)
    fun closeDb() {
        db.close()
    }

    @Test
    @Throws(Exception::class)
    fun insertAndGetWord() {
        runBlocking {
            val word = Word("word")
            wordDao.insert(word)
            val allWords = wordDao.getAlphabetizedWords().waitForValue()
            assertThat(allWords[0].word).isEqualTo(word.word)
        }
    }
}

我还使用了Android插件版本3.4.2。我从here

获得了配置

答案 14 :(得分:0)

我将这个错误归结为只是将fun设置为private,消除了这个错误,这对我来说就解决了。

答案 15 :(得分:0)

更改

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

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

为我工作。

答案 16 :(得分:0)

如果在添加以下依赖项之后:

testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.1'
androidTestImplementation 
           'com.android.support.test.espresso:espresso-core:3.0.1'

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

不能使用属于AndroidJUnit4包的已弃用的androidx.test.runner类,而不是使用属于androidx.test.ext.junit.runners.AndroidJUnit4包的类。

我仍然不理解为什么AndroidJUnit4类被弃用,而Android团队在任何地方(即Codelabsdocs

答案 17 :(得分:0)

您可以使用@JvmField。从文档

  

指示Kotlin编译器不要为此属性生成getter / setter,并将其公开为字段

@Rule
@JvmField
val activityActivityTestRule = ActivityScenarioRule<MainActivity>(MainActivity::class.java)

答案 18 :(得分:0)

对我来说,问题是@Rule注释。.
我现在不知道原因。

作为一种临时的解决方法,您可以例如使用UIAutomator for ActivityTestRule启动您的活动。