"DataPoint field samples must be public" 在 Kotlin 中使用 JUnit 4 Theories 时出错
"DataPoint field samples must be public" error when using JUnit 4 Theories in Kotlin
概览
在 Kotlin class 中将 @DataPoint
或 @DataPoints
应用于 属性 会导致 "DataPoint field samples must be public" 错误。
描述
JUnit4 中的理论使用 @DataPoint
和 @DataPoints
注释来标记示例数据,这些数据被收集并传递给可以将它们作为参数的单独测试。当这些注解应用于 Kotlin 属性(也必须注解 @JvmStatic 并在伴随对象中声明)时,测试用例会失败并显示错误 "DataPoint field samples must be public"。默认情况下,Kotlin 属性应该是 public。此外,显式添加 "public" 修饰符没有任何影响。
示例代码
import org.junit.runner.RunWith
import org.junit.experimental.theories.Theories
import org.junit.experimental.theories.DataPoints
import org.junit.experimental.theories.Theory
import org.junit.Assume.*
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.Matchers.*
@RunWith(Theories::class)
class SampleTheories {
companion object {
@JvmStatic
@DataPoints
public val samples = listOf(
-8, -1, 0, 1, 2, 4, 8
)
}
@Theory
fun triangleInequality(a:Int, b:Int) {
assumeThat(a, `is`(greaterThan(0)))
assumeThat(b, `is`(greaterThan(0)))
assertThat(a+b, `is`(greaterThan(a)))
assertThat(a+b, `is`(greaterThan(b)))
}
}
Gradle 依赖关系
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.2.51"
// ...
testImplementation 'junit:junit:4.12'
testImplementation 'org.hamcrest:hamcrest-library:1.3'
// ...
}
其他系统信息
- Android Studio 3.1.3
- gradle 4.4
- Android gradle 插件 3.1.3
这可能是因为 Kotlin 不知道注释应该放在字节码中的什么位置。这意味着实际代码将类似于:
private static List<Integer> samples = ....
@DataPoints
public static List<Integer> getSamples() {
return this.samples;
}
将 @JvmStatic
替换为 @JvmField
应该会生成正确的代码。如果您使用的是 IntelliJ,您始终可以使用 Inspect Kotlin Bytecode
命令来检查正在生成的代码。
在幕后,Kotlin 中的 public 属性有一个私有支持字段和 public 访问器。在 Java 端(这是 JUnit4 运行的地方),Kotlin 属性本身并不存在。相反,必须显式使用字段和访问器方法。
出现错误是因为注释应用于(私有)字段,而不是 (public) 访问器。
有几个决议:
将 @DataPoints
注释应用于 属性 的 getter:
@JvmStatic
val samples = listOf(
-8, -1, 0, 1, 2, 4, 8
) @DataPoints get
这只会计算一次表达式。
将数据点声明为方法,而不是 属性:
@JvmStatic
@DataPoints
fun samples = listOf(
-8, -1, 0, 1, 2, 4, 8
)
由于数据点源是一个函数,每次检索它们时(可能不是很多次;我不熟悉 Theories 的内部结构),都会重新计算表达式。
概览
在 Kotlin class 中将 @DataPoint
或 @DataPoints
应用于 属性 会导致 "DataPoint field samples must be public" 错误。
描述
JUnit4 中的理论使用 @DataPoint
和 @DataPoints
注释来标记示例数据,这些数据被收集并传递给可以将它们作为参数的单独测试。当这些注解应用于 Kotlin 属性(也必须注解 @JvmStatic 并在伴随对象中声明)时,测试用例会失败并显示错误 "DataPoint field samples must be public"。默认情况下,Kotlin 属性应该是 public。此外,显式添加 "public" 修饰符没有任何影响。
示例代码
import org.junit.runner.RunWith
import org.junit.experimental.theories.Theories
import org.junit.experimental.theories.DataPoints
import org.junit.experimental.theories.Theory
import org.junit.Assume.*
import org.hamcrest.MatcherAssert.assertThat
import org.hamcrest.Matchers.*
@RunWith(Theories::class)
class SampleTheories {
companion object {
@JvmStatic
@DataPoints
public val samples = listOf(
-8, -1, 0, 1, 2, 4, 8
)
}
@Theory
fun triangleInequality(a:Int, b:Int) {
assumeThat(a, `is`(greaterThan(0)))
assumeThat(b, `is`(greaterThan(0)))
assertThat(a+b, `is`(greaterThan(a)))
assertThat(a+b, `is`(greaterThan(b)))
}
}
Gradle 依赖关系
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.2.51"
// ...
testImplementation 'junit:junit:4.12'
testImplementation 'org.hamcrest:hamcrest-library:1.3'
// ...
}
其他系统信息
- Android Studio 3.1.3
- gradle 4.4
- Android gradle 插件 3.1.3
这可能是因为 Kotlin 不知道注释应该放在字节码中的什么位置。这意味着实际代码将类似于:
private static List<Integer> samples = ....
@DataPoints
public static List<Integer> getSamples() {
return this.samples;
}
将 @JvmStatic
替换为 @JvmField
应该会生成正确的代码。如果您使用的是 IntelliJ,您始终可以使用 Inspect Kotlin Bytecode
命令来检查正在生成的代码。
在幕后,Kotlin 中的 public 属性有一个私有支持字段和 public 访问器。在 Java 端(这是 JUnit4 运行的地方),Kotlin 属性本身并不存在。相反,必须显式使用字段和访问器方法。
出现错误是因为注释应用于(私有)字段,而不是 (public) 访问器。
有几个决议:
将
@DataPoints
注释应用于 属性 的 getter:@JvmStatic val samples = listOf( -8, -1, 0, 1, 2, 4, 8 ) @DataPoints get
这只会计算一次表达式。
将数据点声明为方法,而不是 属性:
@JvmStatic @DataPoints fun samples = listOf( -8, -1, 0, 1, 2, 4, 8 )
由于数据点源是一个函数,每次检索它们时(可能不是很多次;我不熟悉 Theories 的内部结构),都会重新计算表达式。