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: /

Geob-o-matic
quelle
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 .

desseim
quelle
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)
jkschneider
quelle
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)
Zahidur Rahman Faisal
quelle
Möchten Sie eine Erklärung hinzufügen?
Peterchaula
12

Mit Kotlin 1.0.4:

val mActivityRule: ...
    @Rule get
Janin
quelle
Dies gibt keine Antwort auf die Frage. Sobald Sie einen ausreichenden Ruf haben, können Sie jeden Beitrag kommentieren . Geben Sie stattdessen Antworten, die nicht vom Fragesteller geklärt werden müssen . - Von der Überprüfung
Jignesh Ansodariya
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.

Marci
quelle