web-dev-qa-db-de.com

Junit4-Tests auf Android migrieren: Welche Ursachen für 'Delegate Runner' konnten nicht geladen werden?

Ich migriere meine App zu Androidx, ich kann meine Unit-Tests nicht zum Laufen bringen. Ich habe ein Beispiel von Googles AndroidJunitRunnerSample genommen, das für die Verwendung der neuen Android-API aktualisiert wurde. Beim Versuch, meine Tests auszuführen, erhalte ich die folgende Fehlermeldung:

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

Hier ist mein Modul 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'
}

Und so sind meine Tests aufgebaut:

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
    }

Was mache ich falsch?

12
J. Nuutinen

Durch das Entfernen von @RunWith(AndroidJUnit4.class)-Anmerkungen aus den Testklassen wurde das Problem behoben, obwohl ich nicht wirklich sagen kann, warum oder wie es behoben wurde.

Edit: Okay, ich habe noch ein paar Tests gemacht. Ich habe meine App zu Kotlin migriert und plötzlich fiel mir auf, dass die Tests auch mit der @RunWith-Annotation funktionierten. Folgendes habe ich herausgefunden:

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

Dieser Java-Test schlägt mit dem Delegate runner for AndroidJunit4 could not be loaded-Fehler fehl. Wenn ich jedoch die Annotation @RunWith entferne, funktioniert es. Auch wenn ich das @BeforeClass-Setup durch nur einen @Before ersetze, wie folgt:

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

Die Tests laufen fehlerfrei. Ich musste die Annotation @BeforeClass verwenden, also habe ich gerade @RunWith entfernt.

Aber jetzt, wo ich Kotlin verwende, funktioniert Folgendes (das dem ersten Java-Beispiel entsprechen sollte):

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

}

Ebenso wie Alessandro Biessek in einer Antwort und @Ioane Sharvadze in den Kommentaren sagte, kann der gleiche Fehler mit der @Rule-Anmerkung auftreten. Wenn ich eine Zeile hinzufüge

 @Rule val instantTaskExecutorRule = InstantTaskExecutorRule()

Im Kotlin-Beispiel tritt derselbe Fehler des Delegiertenläufers auf. Dies muss durch ersetzt werden

@get:Rule val instantTaskExecutorRule = InstantTaskExecutorRule()

Erklärung hier .

12
J. Nuutinen

Die Fehlermeldung wird angezeigt, wenn ich die @ Test-Methode lösche.

Sie können versuchen, eine @ Test-Methode zu erstellen und auszuführen

@Test
public void signInTest() {


}
3
JackWu

Ändern

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

zu

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

funktioniert bei mir.

2
zwlxt

Wenn nach dem Hinzufügen der folgenden Abhängigkeiten:

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'

und

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

hilft dann nicht, die veraltete Klasse AndroidJUnit4 zu verwenden, die zum Paket androidx.test.runner gehört, anstatt zu der, die zum Paket androidx.test.ext.junit.runners.AndroidJUnit4 gehört.

Ich verstehe immer noch nicht, warum die Klasse AndroidJUnit4 Veraltet ist, während die Gradle-Abhängigkeiten, zu denen sie gehört, vom Android) -Team überall vorgeschlagen werden, dh Codelabs und - docs

1
neer17

Sie können @JvmField verwenden. Aus der Dokumentation 

Weist den Kotlin-Compiler an, keine Getter/Setter für diese Eigenschaft zu generieren und sie als Feld anzuzeigen

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

Sie erhalten die Fehlermeldung auch, wenn Sie eine Testregel in Kotlin verwenden und Java-Stil schreiben

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

Sie müssen @Rule in @get:Rule ändern.

@get:Rule
var mainActivityActivityTestRule = ActivityTestRule(MainActivity::class.Java) 
0
Nino Handler

Einige andere mögliche Gründe:

  • Mit nur @SmallTest (Oder Medium-/Large-) Testmethoden. Das Markieren von mindestens einer Methode mit @Test Behebt die Probleme.
  • setup()/teardown() Methoden sind nicht öffentlich.
0
WindRider

Für mich war das Problem die @Rule Annotation ..
Ich kenne die Ursache noch nicht. 

Als temporärer Workaround können Sie beispielsweise Ihre Aktivität mit UIAutomator for ActivityTestRule starten. 

0

Vielleicht haben Sie den Läufer in der Gradle-Konfigurationsdatei nicht aktualisiert? 

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

AndroidStudio 3.2 bietet außerdem eine Option zur Automatisierung der Migration Ihrer Abhängigkeiten zu AndroidX (Refactor -> Migrate to AndroidX ...), die das für mich getan hat. 

0
davisjp

Ich habe mit dieser Konfiguration behoben:

Meine Abhängigkeiten:

/*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 meinem Abschnitt defaultConfig habe ich:

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

    testInstrumentationRunnerArguments clearPackageData: 'true'
}

Im Test habe ich:

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

Ich benutze auch das Android Plugin Version 3.4.2. Ich habe die Konfiguration aus hier genommen

0
SHoko

Ich schätze diesen Fehler, um den Spaß einfach als privat zu definieren, und löste diesen Fehler für mich.

0
Jesus Dimrix