Kotlin e o novo ActivityTestRule: o @Rule deve ser público


264

Estou tentando fazer um teste de interface do usuário para meu aplicativo Android no Kotlin. Desde o novo sistema usando ActivityTestRule, não posso fazê-lo funcionar: ele compila corretamente e, em tempo de execução, recebo:

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)

Aqui está como eu declarei mActivityRule:

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

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

   ...
}

Já é público: /


3
Atualmente, Kotlin não suporta fazer campos que estão apoiando propriedades públicas, mas estamos trabalhando nisso
Andrey Breslav

Existe um bug rastreando isso?
Geob-o-matic

Respostas:


316

O JUnit permite fornecer regras através de um campo de classe de teste ou de um método getter.

O que você anotou é uma propriedade no Kotlin , que a JUnit não reconhecerá.

Aqui estão as maneiras possíveis de especificar uma regra JUnit no Kotlin:

Através de um método getter anotado

No M13 , o processador de anotação suporta destinos de anotação . Quando você escreve

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

no entanto, a anotação usará o propertydestino por padrão (não visível para Java).

No entanto, você pode anotar o getter de propriedade, que também é público e, portanto, atende aos requisitos de JUnit para um getter de regra:

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

Como alternativa, você pode definir a regra com uma função em vez de uma propriedade (obtendo manualmente o mesmo resultado que com @get:Rule).

Através de um campo público anotado

O Kotlin também permite que o candidato beta compile deterministicamente propriedades dos campos na JVM; nesse caso, as anotações e modificadores se aplicam ao campo gerado. Isso é feito usando a @JvmFieldanotação de propriedade do Kotlin, conforme respondida por @jkschneider .


Nota: certifique-se de prefixar a Ruleanotação com um @caractere, pois agora ela é a única sintaxe suportada para anotações e evite, @publicFieldpois ela será eliminada em breve .


Faz? Eu ainda recebo o erro e ele é público com o M14 (0.14.449) #
Geob-o-matic 10/10

parece precisar do @publicField, mas está obsoleto, então tentei o lateinit conforme sugerido pelo IDE, mas latiu para mim dizendo que o lateinit pode ser aplicado apenas em mutável (o artigo do blog diz o contrário…)
Geob-o-matic,

1
Atualizei minha resposta;) Quanto a lateinit val, ele foi removido no M14 porque não impunha totalmente a imutabilidade do campo, consulte a [postagem do blog de lançamento do M14] (blog.jetbrains.com/kotlin/2015/10/kotlin- m14 está fora /).
desseim 10/10

O que é a anotação @get: Também não funciona na minha situação.
aleksandrbel

252

Com o Kotlin 1.0.0+, isso funciona:

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

1
E resolveu o problema da ferramenta fiapos, queixando-se de que o público era qualificador da regra, era redundante.
Rob

Sim \ @JvmField é crucial ou use-o em vez disso \ @get: Rule
Michał Ziobro

Funciona apenas nos campos finais. Não funcionará para uma regra como var wireMockRule = WireMockRule(wireMockConfig().dynamicPort()).
Abhijit Sarkar


12

Com o Kotlin 1.0.4:

val mActivityRule: ...
    @Rule get

Isso não fornece uma resposta para a pergunta. Depois de ter reputação suficiente, você poderá comentar qualquer postagem ; em vez disso, forneça respostas que não exijam esclarecimentos do solicitante . - Do comentário
Jignesh Ansodariya 10/10

10
@JigneshAnsodariya - fiz uma verificação e esta resposta fornece uma resposta ao que foi solicitado. Mais informações sobre como isso está funcionando podem ser encontradas no seguinte link - kotlinlang.org/docs/reference/…
Praveer Gupta 4/16

Há um problema com essa abordagem. Se você deseja acessar a atividade em teste (por exemplo: assertTrue (activityRule.activity.isFinishing)), o getter de propriedade será chamado, criando assim uma nova regra. Nesse caso, activityRule.activity será nulo.
makovkastar

0

Em vez de @Rule, você deve usar @get:Rule.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.