web-dev-qa-db-fra.com

Migration des tests Junit4 vers androidx: quelles sont les causes "Impossible de charger le coureur délégué"

Je migre mon application vers androidx, je n'arrive pas à faire fonctionner mes tests unitaires. J'ai pris l'exemple de Google AndroidJunitRunnerSample , de Google, qui a été mis à jour pour utiliser la nouvelle API Android. Je reçois le message d'erreur suivant lorsque j'essaie d'exécuter mes tests:

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

Voici mon module 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'
}

Et voici comment mes tests sont structurés:

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
    }

Qu'est-ce que je fais mal?

12
J. Nuutinen

Le fait de supprimer les annotations @RunWith(AndroidJUnit4.class) des classes de test a résolu le problème, bien que je ne puisse pas vraiment dire pourquoi ni comment il a résolu le problème.

Edit: D'accord, j'ai fait d'autres tests. J'ai migré mon application vers Kotlin et, tout à coup, j'ai remarqué que les tests commençaient également à fonctionner avec l'annotation @RunWith. Voici ce que j'ai découvert:

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

Ce test Java échoue avec l'erreur Delegate runner for AndroidJunit4 could not be loaded. Mais si je supprime l'annotation @RunWith, cela fonctionne. De plus, si je remplace la configuration @BeforeClass par une simple @Before, comme ceci:

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

Les tests se dérouleront sans erreur. J'avais besoin d'utiliser l'annotation @BeforeClass, alors je viens de supprimer @RunWith.

Mais maintenant que j'utilise Kotlin, voici ce qui fonctionne (ce qui devrait être égal au premier exemple 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...
    }

}

Aussi, comme Alessandro Biessek a déclaré dans une réponse et @Ioane Sharvadze dans les commentaires, la même erreur peut se produire avec l'annotation @Rule. Si j'ajoute une ligne

 @Rule val instantTaskExecutorRule = InstantTaskExecutorRule()

Pour l'exemple Kotlin, la même erreur de participant délégué se produit. Ceci doit être remplacé par

@get:Rule val instantTaskExecutorRule = InstantTaskExecutorRule()

Explication ici .

12
J. Nuutinen

Vous pouvez utiliser @JvmField. De la documentation 

Ordonne au compilateur Kotlin de ne pas générer de getters/setters pour cette propriété ni de l'exposer sous forme de champ

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

Vous obtenez également le message d'erreur si vous utilisez une règle de test dans Kotlin et l'écrivez en style Java.

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

Vous devez changer @Rule en @get:Rule

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

Pour moi, le problème était l'annotation @Rule ..
Je ne connais pas la cause pour le moment. 

En guise de solution temporaire, vous pouvez par exemple démarrer votre activité avec UIAutomator for ActivityTestRule. 

0
Alessandro Biessek

Peut-être n'avez-vous pas mis à jour le coureur dans le fichier de configuration de Gradle? 

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

En outre, AndroidStudio 3.2 a une option pour automatiser la migration de vos dépendances vers AndroidX (Refactor -> Migration vers AndroidX ...) qui l’a fait pour moi. 

0
davisjp