Kotlin et nouvelle ActivityTestRule: la @Rule doit être publique

264

J'essaie de faire un test d'interface utilisateur pour mon application Android à Kotlin. Depuis le nouveau système utilisant ActivityTestRule, je ne peux pas le faire fonctionner: il se compile correctement et à l'exécution, j'obtiens:

java.lang.Exception: The @Rule 'mActivityRule' must be public.
    at org.junit.internal.runners.rules.RuleFieldValidator.addError(RuleFieldValidator.java:90)
    at org.junit.internal.runners.rules.RuleFieldValidator.validatePublic(RuleFieldValidator.java:67)
    at org.junit.internal.runners.rules.RuleFieldValidator.validateField(RuleFieldValidator.java:55)
    at org.junit.internal.runners.rules.RuleFieldValidator.validate(RuleFieldValidator.java:50)
    at org.junit.runners.BlockJUnit4ClassRunner.validateFields(BlockJUnit4ClassRunner.java:170)
    at org.junit.runners.BlockJUnit4ClassRunner.collectInitializationErrors(BlockJUnit4ClassRunner.java:103)
    at org.junit.runners.ParentRunner.validate(ParentRunner.java:344)
    at org.junit.runners.ParentRunner.<init>(ParentRunner.java:74)
    at org.junit.runners.BlockJUnit4ClassRunner.<init>(BlockJUnit4ClassRunner.java:55)
    at android.support.test.internal.runner.junit4.AndroidJUnit4ClassRunner.<init>(AndroidJUnit4ClassRunner.java:38)
    at android.support.test.runner.AndroidJUnit4.<init>(AndroidJUnit4.java:36)
    at java.lang.reflect.Constructor.constructNative(Native Method)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:417)
    at android.support.test.internal.runner.junit4.AndroidAnnotatedBuilder.buildAndroidRunner(AndroidAnnotatedBuilder.java:57)
    at android.support.test.internal.runner.junit4.AndroidAnnotatedBuilder.runnerForClass(AndroidAnnotatedBuilder.java:45)
    at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:57)
    at org.junit.internal.builders.AllDefaultPossibilitiesBuilder.runnerForClass(AllDefaultPossibilitiesBuilder.java:29)
    at org.junit.runner.Computer.getRunner(Computer.java:38)
    at org.junit.runner.Computer$1.runnerForClass(Computer.java:29)
    at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:57)
    at org.junit.runners.model.RunnerBuilder.runners(RunnerBuilder.java:98)
    at org.junit.runners.model.RunnerBuilder.runners(RunnerBuilder.java:84)
    at org.junit.runners.Suite.<init>(Suite.java:79)
    at org.junit.runner.Computer.getSuite(Computer.java:26)
    at android.support.test.internal.runner.TestRequestBuilder.classes(TestRequestBuilder.java:691)
    at android.support.test.internal.runner.TestRequestBuilder.build(TestRequestBuilder.java:654)
    at android.support.test.runner.AndroidJUnitRunner.buildRequest(AndroidJUnitRunner.java:329)
    at android.support.test.runner.AndroidJUnitRunner.onStart(AndroidJUnitRunner.java:226)
    at android.app.Instrumentation$InstrumentationThread.run(Instrumentation.java:1584)

Voici comment j'ai déclaré mActivityRule:

RunWith(javaClass<AndroidJUnit4>())
LargeTest
public class RadisTest {

    Rule
    public val mActivityRule: ActivityTestRule<MainActivity> = ActivityTestRule(javaClass<MainActivity>())

   ...
}

Il est déjà public: /

Geob-o-matic
la source
3
Actuellement, Kotlin ne prend pas en charge la publication des champs qui sauvegardent des propriétés, mais nous y travaillons
Andrey Breslav
Y a-t-il un bug qui suit cela?
Geob-o-matic

Réponses:

316

JUnit permet de fournir des règles via un champ de classe de test ou une méthode getter.

Ce que vous avez annoté est cependant dans Kotlin une propriété que JUnit ne reconnaîtra pas.

Voici les façons possibles de spécifier une règle JUnit dans Kotlin:

Grâce à une méthode getter annotée

Depuis M13 , le processeur d' annotation prend en charge les cibles d'annotation . Quand tu écris

@Rule
public val mActivityRule: ActivityTestRule<MainActivity> = ActivityTestRule(javaClass<MainActivity>())

cependant, l'annotation utilisera la propertycible par défaut (non visible par Java).

Vous pouvez toutefois annoter le getter de propriété, qui est également public et satisfait ainsi les exigences JUnit pour un getter de règles:

@get:Rule
public val mActivityRule: ActivityTestRule<MainActivity> = ActivityTestRule(javaClass<MainActivity>())

Alternativement, vous pouvez définir la règle avec une fonction au lieu d'une propriété (en obtenant manuellement le même résultat qu'avec @get:Rule).

À travers un domaine public annoté

Kotlin permet également au candidat bêta de compiler de manière déterministe les propriétés des champs sur la JVM, auquel cas les annotations et les modificateurs s'appliquent au champ généré. Cela se fait en utilisant l' @JvmFieldannotation de propriété de Kotlin comme l'a répondu @jkschneider .


Remarque: assurez-vous de préfixer l' Ruleannotation avec un @caractère car c'est maintenant la seule syntaxe prise en charge pour les annotations , et évitez-la @publicFieldcar elle sera bientôt supprimée .

desseim
la source
Le fait-il? J'ai toujours l'erreur et c'est public avec M14 (0.14.449)
Geob-o-matic
semble avoir besoin de @publicField, mais il est obsolète, j'ai donc essayé le Lateinit comme suggéré par l'IDE, mais ensuite il aboie en me disant que le Lateinit ne peut être appliqué que sur mutable (l'article du blog dit le contraire…)
Geob-o-matic
1
Mis à jour ma réponse;) Quant à lateinit val, il a été supprimé dans M14 car il n'a pas pleinement appliqué l'immuabilité du champ, voir le [blog de la version M14] (blog.jetbrains.com/kotlin/2015/10/kotlin- m14-is-out /).
desseim
Qu'est-ce que @get: annotation? Cela ne fonctionne pas non plus dans ma situation.
aleksandrbel
252

Avec Kotlin 1.0.0+, cela fonctionne:

@Rule @JvmField 
val mActivityRule = ActivityTestRule(MainActivity::class.java)
jkschneider
la source
1
Et cela a résolu le problème de l'outil anti-peluches se plaignant que le public était qualifié sur la règle était redondant.
Rob
Oui \ @JvmField est crucial ou utilisez plutôt \ @get: Rule
Michał Ziobro
Fonctionne uniquement sur les champs finaux. Ne fonctionnera pas pour une règle comme var wireMockRule = WireMockRule(wireMockConfig().dynamicPort()).
Abhijit Sarkar
17

Utilisez ceci:

@get:Rule
var mActivityRule: ActivityTestRule<MainActivity> = ActivityTestRule(MainActivity::class.java)
Zahidur Rahman Faisal
la source
Voulez-vous ajouter une explication?
peterchaula le
12

Avec Kotlin 1.0.4:

val mActivityRule: ...
    @Rule get
janin
la source
Cela ne fournit pas de réponse à la question. Une fois que vous avez une réputation suffisante, vous pourrez commenter n'importe quel message ; fournissez plutôt des réponses qui ne nécessitent pas de clarification de la part du demandeur . - De l'avis
Jignesh Ansodariya
10
@JigneshAnsodariya - J'ai fait une vérification et cette réponse fournit une réponse à ce qui a été demandé. Plus d'informations sur la façon dont cela fonctionne peuvent être trouvées sur le lien suivant - kotlinlang.org/docs/reference/…
Praveer Gupta
Il y a un problème avec cette approche. Si vous souhaitez accéder à l'activité en cours de test (par exemple: assertTrue (activityRule.activity.isFinishing)), le getter de propriété sera appelé, créant ainsi une nouvelle règle. Dans ce cas, activityRule.activity sera null.
makovkastar
0

Au lieu de @Rule, vous devez utiliser @get:Rule.

Marci
la source