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>())

   ...
}

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

Geob-O-Matic
источник
3
В настоящее время Kotlin не поддерживает обнародование полей, поддерживающих свойства, но мы работаем над этим
Андрей Бреслав,
Есть ли ошибка отслеживания этого?
Geob-o-matic
2
youtrack.jetbrains.com/issue/KT-3441
Андрей Бреслав

Ответы:

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поскольку он скоро будет удален .

desseim
источник
Является ли? Я все еще получаю ошибку, и это общедоступно с 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)
jkschneider
источник
1
И это решило проблему инструмента lint, жалуясь на то, что публика определяла правило, было избыточным.
Роб
Да \ @JvmField имеет решающее значение или использовать скорее \ @get: Правило
Михал Зиобро
Работает только на финальных полях. Не будет работать как правило var wireMockRule = WireMockRule(wireMockConfig().dynamicPort()).
Абхиджит Саркар
17

Использовать это:

@get:Rule
var mActivityRule: ActivityTestRule<MainActivity> = ActivityTestRule(MainActivity::class.java)
Захидур Рахман Фейсал
источник
Хотите добавить объяснение?
peterchaula
12

С Kotlin 1.0.4:

val mActivityRule: ...
    @Rule get
Янин
источник
Это не дает ответа на вопрос. Как только у вас будет достаточно репутации, вы сможете комментировать любой пост ; вместо этого предоставьте ответы, которые не требуют разъяснений от автора . - Из обзора
Джинеш Ансодария
10
@JigneshAnsodariya - я сделал проверку, и этот ответ дает ответ на вопрос, который был задан. Дополнительную информацию о том, как это работает, можно найти по следующей ссылке - kotlinlang.org/docs/reference/…
Praveer Gupta
Есть проблема с этим подходом. Если вы хотите получить доступ к тестируемому действию (например, assertTrue (activityRule.activity.isFinishing)), будет вызван метод получения свойства, что создаст новое правило. В этом случае ActivityRule.activity будет нулевым.
Маковкастар
0

Вместо этого @Ruleвы должны использовать @get:Rule.

Марси
источник