Kotlin и новый ActivityTestRule: @Rule должен быть публичным


264

Я пытаюсь сделать тест интерфейса для моего приложения для Android в Kotlin. Поскольку новая система использует ActivityTestRule, я не могу заставить ее работать: она компилируется правильно, и во время выполнения я получаю:

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)

Вот как я объявил mActivityRule:

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

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

   ...
}

Это уже публично: /


3
В настоящее время Kotlin не поддерживает обнародование полей, поддерживающих свойства, но мы работаем над этим
Андрей Бреслав,

Есть ли ошибка отслеживания этого?
Geob-o-matic

Ответы:


316

JUnit позволяет предоставлять правила через поле тестового класса или метод получения.

Тем не менее, в Kotlin вы аннотировали свойство , которое JUnit не распознает.

Вот возможные способы указать правило JUnit в Kotlin:

С помощью аннотированного метода получения

Начиная с M13 , процессор аннотаций поддерживает цели аннотаций . Когда ты пишешь

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

тем не менее, аннотация будет использовать propertyцель по умолчанию (не видимый для Java).

Однако вы можете аннотировать свойство get, которое также является общедоступным и, таким образом, удовлетворяет требованиям JUnit для правила get:

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

В качестве альтернативы вы можете определить правило с помощью функции вместо свойства (получая вручную тот же результат, что и с @get:Rule).

Через аннотированное публичное поле

Kotlin также позволяет, поскольку бета-кандидат детерминистически компилирует свойства полей в JVM, и в этом случае аннотации и модификаторы применяются к сгенерированному полю. Это делается с помощью @JvmFieldаннотации свойств Kotlin, на которую отвечает @jkschneider .


Примечание: обязательно добавьте Ruleаннотацию к @символу, так как теперь это единственный поддерживаемый синтаксис для аннотаций , и избегайте, @publicFieldпоскольку он скоро будет удален .


Является ли? Я все еще получаю ошибку, и это общедоступно с M14 (0.14.449)
Geob-o-matic

Кажется, нужен @publicField, но он устарел, поэтому я попробовал lateinit, как это было предложено в IDE, но потом он гавкает на меня, говоря, что lateinit можно применять только к изменяемым (в статье блога сказано иначе…)
Geob-o-matic

1
Обновил мой ответ;) Что касается lateinit val, он был удален в M14, так как он не полностью обеспечивал неизменность поля, см. [Сообщение в блоге о выпуске M14] (blog.jetbrains.com/kotlin/2015/10/kotlin- M14-это выход /).
desseim

Что такое @get: аннотация? Это также не работает в моей ситуации.
Александрбель

252

С Kotlin 1.0.0+ это работает:

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

1
И это решило проблему инструмента lint, жалуясь на то, что публика определяла правило, было избыточным.
Роб

Да \ @JvmField имеет решающее значение или использовать скорее \ @get: Правило
Михал Зиобро

Работает только на финальных полях. Не будет работать как правило var wireMockRule = WireMockRule(wireMockConfig().dynamicPort()).
Абхиджит Саркар


12

С Kotlin 1.0.4:

val mActivityRule: ...
    @Rule get

Это не дает ответа на вопрос. Как только у вас будет достаточно репутации, вы сможете комментировать любой пост ; вместо этого предоставьте ответы, которые не требуют разъяснений от автора . - Из обзора
Джинеш Ансодария

10
@JigneshAnsodariya - я сделал проверку, и этот ответ дает ответ на вопрос, который был задан. Дополнительную информацию о том, как это работает, можно найти по следующей ссылке - kotlinlang.org/docs/reference/…
Praveer Gupta

Есть проблема с этим подходом. Если вы хотите получить доступ к тестируемому действию (например, assertTrue (activityRule.activity.isFinishing)), будет вызван метод получения свойства, что создаст новое правило. В этом случае ActivityRule.activity будет нулевым.
Маковкастар

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.