将Junit4测试迁移到androidx:是什么导致';无法加载代理运行程序';?

将Junit4测试迁移到androidx:是什么导致';无法加载代理运行程序';?,android,junit,junit4,androidx,Android,Junit,Junit4,Androidx,我正在将我的应用程序迁移到androidx,我的单元测试似乎无法正常工作。我以中的示例为例,它已更新为使用新的androidx api。尝试运行测试时出现以下错误: java.lang.Exception: Delegate runner 'androidx.test.internal.runner.junit4.AndroidJUnit4ClassRunner' for AndroidJUnit4 could not be loaded. Check your build configurat

我正在将我的应用程序迁移到androidx,我的单元测试似乎无法正常工作。我以中的示例为例,它已更新为使用新的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
    }

我做错了什么?

也许您没有更新gradle配置文件中的跑步者

defaultConfig {
    ...
    testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
另外,AndroidStudio 3.2还提供了一个选项,可以自动将依赖项迁移到AndroidX(重构->迁移到AndroidX…),我就是这么做的

从测试类中删除
@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....
    }
}
测试将无错误地运行。我需要使用
@BeforeClass
注释,所以我刚刚删除了
@RunWith

但是现在我正在使用Kotlin,下面的内容(应该与第一个java示例相同)可以工作:

此外,正如在回答和评论中所说的,@Ioane Sharvadze,
@Rule
注释也可能发生同样的错误。如果我加一行

 @Rule val instantTaskExecutorRule = InstantTaskExecutorRule()
对于Kotlin示例,同样的委托运行程序错误也会发生。这必须被替换为

@get:Rule val instantTaskExecutorRule = InstantTaskExecutorRule()

解释。

对我来说,问题在于
@规则
注释。
我现在不知道原因


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

您可以使用
@JvmField
。从文件

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

@规则
@JvmField
val activityActivityTestRule=ActivityScenarioRule(MainActivity::class.java)

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

@Rule
var mainActivityActivityTestRule = ActivityTestRule(MainActivity::class.java)
您必须将
@Rule
更改为
@get:Rule

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

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

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'

然后使用不推荐使用的
AndroidJUnit4
类,该类属于
androidx.test.runner
包,而不是属于
androidx.test.ext.junit.runners.AndroidJUnit4


我仍然不明白为什么
AndroidJUnit4
类被弃用,而它所属的Gradle依赖项是由Android团队建议的,即删除@Test方法时显示的错误消息

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

@Test
public void signInTest() {


}
改变

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


对我有效。

我排除了这个错误,只需将fun设置为private,删除它就可以解决这个问题。

我修复了这个配置:

我的依赖项:

/*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。我从

中获取了配置,还有其他一些可能的原因:

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

    • 测试框架实际上提供的信息太少。我遇到了同样的问题,深入研究了堆栈跟踪,发现了以下验证:


      因此您必须在类之前声明
      @BeforeClass
      方法
      static

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

      解决方案1: 生成-->清理项目。然后构建-->重建项目

      解决方案2: 有两个包具有AndroidJUnit4的版本

    • androidx.test.runner
      (已弃用)
    • androidx.test.ext.junit.runners
    • 确保您的build.gradle(应用程序)具有此行

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

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

      至于我的情况,定义函数参数是个问题

      @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.
          // ...
      }
      

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

      @Rule
      public ActivityTestRule<YourActivity> activityTestRule = new ActivityTestRule<>(YourActivity.class); 
      
      @规则
      public ActivityTestRule ActivityTestRule=新的ActivityTestRule(YourActivity.class);
      
      在我的例子中,我通过显式地将所有
      @Test
      方法声明为
      public
      ,并将
      @AfterClass
      方法声明为
      public static

      如果您将这些方法中的任何一个保留为隐式/显式
      受保护
      ,或显式
      私有
      ;您将遇到以下异常

      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() {
      
      }
      
      而不是:

      @Before
      void setUp() {
      
      }
      
      @Before
      protected void setUp() {
      
      }
      
      @Before
      private void setUp() {
      
      }
      
      @BeforeClass
      public void init() {
      
      }
      

      AndroidJUnit4在类或超类中都不支持带有
      @Test
      注释的函数中:

      • 参数:
        @Test-fun-dontWork(param:String){}
      • 私有访问修饰符:
        @testprivate-fun-dontWork2(){}
      注:如果没有
      @Test
      注释,则允许进行上述操作


      预期的方式可以是:

      ClassTest.kt build.gradle(:mobile)
      GL

      您需要确保任何标有@BeforeClass注释的类都是公共静态的。例如:

      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
          }
      

      在我的例子中,我跳过了用
      @test
      注释测试用例。这不是你的情况。这个答案适用于像我这样的其他人。

      似乎我已经在build.gradle中设置了TestInstrumentRunner,并且我也完成了“迁移到AndroidX”重构。但现在,测试是JUnit测试。对我来说,问题是我使用的是
      @Rule
      而不是
      @get:Rule
      一个
      @Rule
      public ActivityTestRule<YourActivity> activityTestRule = new ActivityTestRule<>(YourActivity.class); 
      
      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() {
      
      }
      
      @Before
      void setUp() {
      
      }
      
      @Before
      protected void setUp() {
      
      }
      
      @Before
      private void setUp() {
      
      }
      
      @BeforeClass
      public void init() {
      
      }
      
      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) {}
      
      }
      
      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'
      } 
      
      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
          }