Migrating Junit4 tests to androidx: What causes 'delegate runner could not be loaded'?

后端 未结 19 1800
长情又很酷
长情又很酷 2020-12-05 06:35

I am migrating my app to androidx, I can\'t seem to get my unit tests working. I took example from Google\'s AndroidJunitRunnerSample, which has been updated to use the new

相关标签:
19条回答
  • 2020-12-05 06:38

    Some other possible reasons:

    • Having only @SmallTest (or Medium-/Large-) test methods. Marking at least one method with @Test solves the issues.
    • setup() / teardown() methods are not public.
    0 讨论(0)
  • 2020-12-05 06:39

    If after adding the following dependencies:

    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'
    

    and

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

    doesn't help then use the deprecated AndroidJUnit4 class which belongs to the androidx.test.runner package instead of the one belongs to androidx.test.ext.junit.runners.AndroidJUnit4 package.

    I still don't understand why AndroidJUnit4 class is deprecated while the Gradle dependencies it belongs to is suggested by the Android team everywhere i.e Codelabs and docs

    0 讨论(0)
  • 2020-12-05 06:40

    You also get the error message if you use a test rule in Kotlin and write it Java style

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

    You have to change @Rule to @get:Rule

    @get:Rule
    var mainActivityActivityTestRule = ActivityTestRule(MainActivity::class.java) 
    
    0 讨论(0)
  • 2020-12-05 06:41

    Removing @RunWith(AndroidJUnit4.class) annotations from the test classes fixed the issue, although I can't really say why or how it fixed it.

    Edit: Allright I did some more testing. I migrated my app to Kotlin, and suddenly I noticed the tests began to work with the @RunWith annotation, too. Here's what I found out:

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

    This java test fails with the Delegate runner for AndroidJunit4 could not be loaded error. But If I remove the @RunWith annotation, it works. Also, if I replace the @BeforeClass setup with just a @Before, like this:

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

    The tests will run without errors. I needed to use the @BeforeClass annotation, so I just removed @RunWith.

    But now that I am using Kotlin, the following (which should be equal to the first java example) works:

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

    Also, as Alessandro Biessek said in an answer and @Ioane Sharvadze in the comments, the same error can happen with the @Rule annotation. If I add a line

     @Rule val instantTaskExecutorRule = InstantTaskExecutorRule()
    

    To the Kotlin example, the same delegate runner error happens. This must be replaced with

    @get:Rule val instantTaskExecutorRule = InstantTaskExecutorRule()
    

    Explanation here.

    0 讨论(0)
  • 2020-12-05 06:41

    I fixed with this configuration:

    My dependencies:

    /*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"
    

    In my defaultConfig section I have:

    defaultConfig {
        applicationId "uy.edu.ude.archcomponents"
        minSdkVersion 22
        targetSdkVersion 28
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    
        testInstrumentationRunnerArguments clearPackageData: 'true'
    }
    

    In the test I have:

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

    I also use the android plugin version 3.4.2. I took the config from here

    0 讨论(0)
  • 2020-12-05 06:45

    For me the problem was the @Rule annotation..
    I don't know the cause for now.

    As a temporary workaround yo can for example start your activity using UIAutomator for ActivityTestRule.

    0 讨论(0)
提交回复
热议问题