Kotlin y la nueva ActivityTestRule: la @Rule debe ser pública

264

Estoy tratando de hacer una prueba de IU para mi aplicación de Android en Kotlin. Desde el nuevo sistema que usa ActivityTestRule, no puedo hacer que funcione: se compila correctamente, y en tiempo de ejecución, obtengo:

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)

Así es como declaró mActivityRule:

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

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

   ...
}

Ya es público: /

Geob-o-matic
fuente
3
Actualmente, Kotlin no admite hacer públicos los campos que respaldan propiedades, pero estamos trabajando en ello
Andrey Breslav
¿Hay algún error que rastree esto?
Geob-o-matic

Respuestas:

316

JUnit permite proporcionar reglas a través de un campo de clase de prueba o un método getter.

Sin embargo, lo que anotó es en Kotlin una propiedad , que JUnit no reconocerá.

Estas son las posibles formas de especificar una regla JUnit en Kotlin:

A través de un método getter anotado

Desde M13 , el procesador de anotación admite objetivos de anotación . Cuando escribes

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

sin embargo, la anotación usará el propertydestino por defecto (no visible para Java).

Sin embargo, puede anotar el captador de propiedades, que también es público y, por lo tanto, cumple los requisitos de JUnit para un captador de reglas:

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

Alternativamente, puede definir la regla con una función en lugar de una propiedad (logrando manualmente el mismo resultado que con @get:Rule).

A través de un campo público anotado

Kotlin también permite, ya que el candidato beta, compilar de manera determinista las propiedades de los campos en la JVM, en cuyo caso las anotaciones y modificadores se aplican al campo generado. Esto se hace usando la @JvmFieldanotación de propiedad de Kotlin según lo respondió @jkschneider .


Nota al margen: asegúrese de prefijar la Ruleanotación con un @carácter, ya que ahora es la única sintaxis compatible para las anotaciones , y evite @publicFieldya que pronto se descartará .

desseim
fuente
¿Lo hace? Todavía recibo el error y es público con M14 (0.14.449)
Geob-o-matic
parece necesitar @publicField, pero está en desuso, así que probé lateinit según lo sugerido por IDE, pero luego me ladró diciendo que lateinit solo se puede aplicar en mutable (el artículo del blog dice lo contrario ...)
Geob-o-matic
1
Actualicé mi respuesta;) En cuanto a lateinit val, se ha eliminado en M14 ya que no imponía completamente la inmutabilidad del campo, consulte la [publicación del blog de lanzamiento de M14] (blog.jetbrains.com/kotlin/2015/10/kotlin- m14-is-out /).
desseim
¿Qué es @get: anotación? Tampoco funciona en mi situación.
aleksandrbel
252

Con Kotlin 1.0.0+, esto funciona:

@Rule @JvmField 
val mActivityRule = ActivityTestRule(MainActivity::class.java)
jkschneider
fuente
1
Y resolvió el problema de la herramienta de pelusa quejándose de que el público calificaba en la regla era redundante.
Rob
Sí \ @JvmField es crucial o use más bien \ @get: Rule
Michał Ziobro
Solo funciona en campos finales. No funcionará para una regla como var wireMockRule = WireMockRule(wireMockConfig().dynamicPort()).
Abhijit Sarkar
17

Utilizar este:

@get:Rule
var mActivityRule: ActivityTestRule<MainActivity> = ActivityTestRule(MainActivity::class.java)
Zahidur Rahman Faisal
fuente
¿Quieres añadir una explicación?
Peterter
12

Con Kotlin 1.0.4:

val mActivityRule: ...
    @Rule get
janin
fuente
Esto no proporciona una respuesta a la pregunta. Una vez que tenga suficiente reputación , podrá comentar cualquier publicación ; en su lugar, proporcione respuestas que no requieran una aclaración del autor de la pregunta . - De la opinión
Jignesh Ansodariya
10
@JigneshAnsodariya: hice una comprobación y esta respuesta proporciona una respuesta a lo que se ha pedido. Puede encontrar más información sobre cómo funciona esto en el siguiente enlace: kotlinlang.org/docs/reference/…
Praveer Gupta
Hay un problema con este enfoque. Si desea acceder a la actividad bajo prueba (por ejemplo: afirmar verdadero (activityRule.activity.isFinishing)), se llamará al captador de propiedades, creando así una nueva regla. En este caso, activityRule.activity será nulo.
makovkastar
0

En lugar de @Rule, deberías usar @get:Rule.

Marci
fuente