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?
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 .
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() {
}
Ändern
@Test
void someTest() {
// Testing here
}
zu
@Test
public void someTest() {
// Testing here
}
funktioniert bei mir.
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
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)
Einige andere mögliche Gründe:
@SmallTest
(Oder Medium-/Large-) Testmethoden. Das Markieren von mindestens einer Methode mit @Test
Behebt die Probleme.setup()
/teardown()
Methoden sind nicht öffentlich.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.
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.
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
Ich schätze diesen Fehler, um den Spaß einfach als privat zu definieren, und löste diesen Fehler für mich.