Kotlin e nuovo ActivityTestRule: @Rule deve essere pubblico


264

Sto cercando di eseguire il test dell'interfaccia utente per la mia app Android in Kotlin. Poiché il nuovo sistema che utilizza ActivityTestRule, non riesco a farlo funzionare: si compila correttamente e in fase di esecuzione ottengo:

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)

Ecco come ho dichiarato mActivityRule:

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

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

   ...
}

È già pubblico: /


3
Attualmente, Kotlin non supporta la creazione di campi che supportano le proprietà pubbliche, ma ci stiamo lavorando
Andrey Breslav

C'è un bug che sta monitorando questo?
Geob-o-matic,

Risposte:


316

JUnit consente di fornire regole attraverso un campo della classe di test o un metodo getter.

Ciò che hai annotato in Kotlin è una proprietà , che JUnit non riconoscerà.

Ecco i modi possibili per specificare una regola JUnit in Kotlin:

Attraverso un metodo getter annotato

Da M13 , il processore delle annotazioni supporta le destinazioni delle annotazioni . Quando scrivi

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

tuttavia, l'annotazione utilizzerà la propertydestinazione per impostazione predefinita (non visibile a Java).

Tuttavia, è possibile annotare il getter di proprietà, che è anche pubblico e quindi soddisfa i requisiti JUnit per un getter di regole:

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

In alternativa, è possibile definire la regola con una funzione anziché con una proprietà (ottenendo manualmente lo stesso risultato di con @get:Rule).

Attraverso un campo pubblico annotato

Kotlin consente inoltre, dal momento che il candidato beta, di compilare in modo deterministico le proprietà nei campi della JVM, nel qual caso le annotazioni e i modificatori si applicano al campo generato. Questo viene fatto usando l' @JvmFieldannotazione della proprietà di Kotlin come risposta da @jkschneider .


Nota a margine: assicurati di aggiungere il prefisso Ruleall'annotazione con un @carattere in quanto ora è l'unica sintassi supportata per le annotazioni ed evita @publicFieldpoiché verrà presto eliminata .


Vero? Ricevo ancora l'errore ed è pubblico con M14 (0.14.449)
Geob-o-matic,

sembra aver bisogno di @publicField, ma è deprecato, quindi ho provato lateinit come suggerito da IDE, ma poi mi abbaia dicendo che lateinit può essere applicato solo su mutable (l'articolo del blog dice diversamente ...)
Geob-o-matic

1
Aggiornato la mia risposta;) Per quanto riguarda lateinit val, è stato rimosso in M14 poiché non imponeva completamente l'immutabilità del campo, vedere il [post sul blog della versione M14] (blog.jetbrains.com/kotlin/2015/10/kotlin- m14-è-out /).
desseim

Che cos'è @get: annotation? Inoltre non funziona nella mia situazione.
Aleksandrbel,

252

Con Kotlin 1.0.0+, funziona:

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

1
E ha risolto il problema dello strumento lanugine lamentando che il pubblico era qualificatore della regola era ridondante.
Rob,

Sì \ @JvmField è cruciale o usa piuttosto \ @get: Rule
Michał Ziobro

Funziona solo sui campi finali. Non funzionerà per una regola come var wireMockRule = WireMockRule(wireMockConfig().dynamicPort()).
Abhijit Sarkar,


12

Con Kotlin 1.0.4:

val mActivityRule: ...
    @Rule get

Questo non fornisce una risposta alla domanda. Una volta che hai una reputazione sufficiente , sarai in grado di commentare qualsiasi post ; fornire invece risposte che non richiedono chiarimenti da parte del richiedente . - Dalla recensione
Jignesh Ansodariya,

10
@JigneshAnsodariya - Ho fatto un controllo e questa risposta fornisce una risposta a ciò che è stato chiesto. Maggiori informazioni su come funziona sono disponibili al seguente link - kotlinlang.org/docs/reference/…
Praveer Gupta

C'è un problema con questo approccio. Se si desidera accedere all'attività in prova (ad esempio: assertTrue (activityRule.activity.isFinishing)), verrà chiamato il getter della proprietà, creando così una nuova regola. In questo caso activityRule.activity sarà null.
makovkastar,

0

Invece di @Rule, dovresti usare @get:Rule.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.