Kotlin und neue ActivityTestRule: Die @Rule muss öffentlich sein


264

Ich versuche, einen UI-Test für meine Android-App in Kotlin durchzuführen. Da das neue System ActivityTestRule verwendet, kann ich es nicht zum Laufen bringen: Es wird korrekt kompiliert und zur Laufzeit wird Folgendes angezeigt:

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)

So habe ich mActivityRule deklariert:

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

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

   ...
}

Es ist bereits öffentlich: /


3
Derzeit unterstützt Kotlin nicht die
Veröffentlichung von

Gibt es einen Fehler, der dies verfolgt?
Geob-o-matic

Antworten:


316

Mit JUnit können Regeln über ein Testklassenfeld oder eine Getter-Methode bereitgestellt werden.

Was Sie kommentiert haben, ist in Kotlin eine Eigenschaft , die JUnit nicht erkennt.

Hier sind die möglichen Möglichkeiten, eine JUnit-Regel in Kotlin anzugeben:

Durch eine kommentierte Getter-Methode

Ab M13 unterstützt der Annotationsprozessor Annotationsziele . Wenn du schreibst

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

In der Anmerkung wird jedoch das verwendet property standardmäßig Ziel (für Java nicht sichtbar).

Sie können jedoch den Property Getter mit Anmerkungen versehen, der ebenfalls öffentlich ist und somit die JUnit-Anforderungen für einen Rule Getter erfüllt:

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

Alternativ können Sie die Regel mit einer Funktion anstelle einer Eigenschaft definieren (manuell das gleiche Ergebnis wie mit erzielen @get:Rule ).

Durch ein kommentiertes öffentliches Feld

Kotlin ermöglicht es dem Beta-Kandidaten außerdem , Eigenschaften für Felder in der JVM deterministisch zu kompilieren. In diesem Fall gelten die Anmerkungen und Modifikatoren für das generierte Feld. Dies erfolgt mithilfe der Kotlin- @JvmFieldEigenschaftsanmerkung , die von @jkschneider beantwortet wird .


Randnotiz: Stellen Sie sicher, dass der RuleAnnotation ein @Zeichen vorangestellt wird, da dies jetzt die einzige unterstützte Syntax für Annotationen ist , und vermeiden Sie dies, @publicFieldda sie bald gelöscht wird .


Macht es? Ich bekomme immer noch den Fehler und es ist öffentlich mit M14 (0.14.449)
Geob-o-matic

scheint @publicField zu brauchen, aber es ist veraltet, also habe ich lateinit ausprobiert, wie von IDE vorgeschlagen, aber dann bellt es mich an, dass lateinit nur auf veränderliche Elemente angewendet werden kann (der Artikel des Blogs sagt etwas anderes ...)
Geob-o-matic

1
Meine Antwort wurde aktualisiert;) lateinit valSie wurde in M14 entfernt, da sie die Unveränderlichkeit des Feldes nicht vollständig erzwang. Weitere Informationen finden Sie im [M14-Release-Blog-Beitrag] (blog.jetbrains.com/kotlin/2015/10/kotlin- m14-is-out /).
Desseim

Was ist @get: Annotation? Es funktioniert auch nicht in meiner Situation.
Aleksandrbel

252

Mit Kotlin 1.0.0+ funktioniert dies:

@Rule @JvmField 
val mActivityRule = ActivityTestRule(MainActivity::class.java)

1
Und es löste das Problem, dass sich das Flusenwerkzeug beschwerte, dass die Öffentlichkeit als Qualifizierer für die Regel überflüssig sei.
Rob

Ja \ @JvmField ist entscheidend oder verwenden Sie lieber \ @get: Regel
Michał Ziobro

Funktioniert nur auf endgültigen Feldern. Funktioniert nicht für eine Regel wie var wireMockRule = WireMockRule(wireMockConfig().dynamicPort()).
Abhijit Sarkar

17

Benutze das:

@get:Rule
var mActivityRule: ActivityTestRule<MainActivity> = ActivityTestRule(MainActivity::class.java)

Möchten Sie eine Erklärung hinzufügen?
Peterchaula

12

Mit Kotlin 1.0.4:

val mActivityRule: ...
    @Rule get


10
@JigneshAnsodariya - Ich habe eine Überprüfung durchgeführt und diese Antwort gibt eine Antwort auf die Fragen. Weitere Informationen dazu finden Sie unter folgendem Link: kotlinlang.org/docs/reference/…
Praveer Gupta

Bei diesem Ansatz gibt es ein Problem. Wenn Sie auf die zu testende Aktivität zugreifen möchten (z. B. assertTrue (activityRule.activity.isFinishing)), wird der Property Getter aufgerufen, wodurch eine neue Regel erstellt wird. In diesem Fall ist activityRule.activity null.
Makovkastar

0

Stattdessen @Rulesollten Sie verwenden @get:Rule.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.