Kotlin/Mockito:如何从 kotlin.Annotation 模拟 "annotationClass"
Kotlin/Mockito: How to mock "annotationClass" from kotlin.Annotation
我想模拟注释以根据给定的注释检查 returns 结果的 class 的良好行为。
这是我的一项测试,用于检查 OneToOne 注释的良好行为:
@Test
fun <T> supports_when_field_has_OneToOne_annotation_with_eager_fetch_type() {
val myHandler = MyHandler<T>()
val joinAnnotation = mock<OneToOne> {
on { this.fetch }.thenReturn(FetchType.EAGER)
onGeneric { this.annotationClass }.thenReturn(OneToOne::class)
}
val supports = myHandler.supports(joinAnnotation)
assertThat(supports).isTrue()
}
当我运行测试时,出现以下错误:
org.mockito.exceptions.misusing.WrongTypeOfReturnValue:
KClassImpl cannot be returned by annotationType()
annotationType() should return Class
If you're unsure why you're getting above error read on.
Due to the nature of the syntax above problem might occur because:
- This exception might occur in wrongly written multi-threaded tests.
Please refer to Mockito FAQ on limitations of concurrency testing.
- A spy is stubbed using when(spy.foo()).then() syntax. It is safer to stub spies -
- with doReturn|Throw() family of methods. More in javadocs for Mockito.spy() method.
当 mockito 调用以下代码时出现此错误:
onGeneric { this.annotationClass }.thenReturn(OneToOne::class)
如果我删除这一行,我可以毫无问题地模拟 Annotation。 (模拟 'fetch' 属性完美运行),但我的测试没有通过,因为我需要模拟 'annotationClass'
不明白为什么报错,为什么报错与annotationType()(java注解方法)有关?
有人知道如何解决这个问题吗?
我找到了解决问题的方法。
kotlin.Annotation.annotationClass
是kotlin扩展函数:
/**
* Returns a [KClass] instance corresponding to the annotation type of this annotation.
*/
public val <T : Annotation> T.annotationClass: KClass<out T>
get() = (this as java.lang.annotation.Annotation).annotationType().kotlin as KClass<out T>
这个函数调用java.lang.annotation.Annotation.annotationType()
我无法模拟扩展函数,因为 kotlin 将扩展函数转换为静态方法,而 Mockito 无法存根静态方法。
所以我直接嘲笑了java.lang.annotation.Annotation.annotationType()
。
这是我的新代码:
@Test
fun <T> supports_when_field_has_OneToOne_annotation_with_eager_fetch_type() {
val myHandler = MyHandler<T>()
val joinAnnotation = mock<OneToOne> {
on { this.fetch }.thenReturn(FetchType.EAGER)
on { (this as java.lang.annotation.Annotation).annotationType() }.thenReturn(OneToOne::class.java)
}
val supports = myHandler.supports(joinAnnotation)
assertThat(supports).isTrue()
}
有模拟静态方法的替代方法(PowerMock、MockK),但我没有测试。
如果谁有更好的建议,我很想看看
我想模拟注释以根据给定的注释检查 returns 结果的 class 的良好行为。
这是我的一项测试,用于检查 OneToOne 注释的良好行为:
@Test
fun <T> supports_when_field_has_OneToOne_annotation_with_eager_fetch_type() {
val myHandler = MyHandler<T>()
val joinAnnotation = mock<OneToOne> {
on { this.fetch }.thenReturn(FetchType.EAGER)
onGeneric { this.annotationClass }.thenReturn(OneToOne::class)
}
val supports = myHandler.supports(joinAnnotation)
assertThat(supports).isTrue()
}
当我运行测试时,出现以下错误:
org.mockito.exceptions.misusing.WrongTypeOfReturnValue: KClassImpl cannot be returned by annotationType() annotationType() should return Class
If you're unsure why you're getting above error read on. Due to the nature of the syntax above problem might occur because:
- This exception might occur in wrongly written multi-threaded tests. Please refer to Mockito FAQ on limitations of concurrency testing.
- A spy is stubbed using when(spy.foo()).then() syntax. It is safer to stub spies -
- with doReturn|Throw() family of methods. More in javadocs for Mockito.spy() method.
当 mockito 调用以下代码时出现此错误:
onGeneric { this.annotationClass }.thenReturn(OneToOne::class)
如果我删除这一行,我可以毫无问题地模拟 Annotation。 (模拟 'fetch' 属性完美运行),但我的测试没有通过,因为我需要模拟 'annotationClass'
不明白为什么报错,为什么报错与annotationType()(java注解方法)有关?
有人知道如何解决这个问题吗?
我找到了解决问题的方法。
kotlin.Annotation.annotationClass
是kotlin扩展函数:
/**
* Returns a [KClass] instance corresponding to the annotation type of this annotation.
*/
public val <T : Annotation> T.annotationClass: KClass<out T>
get() = (this as java.lang.annotation.Annotation).annotationType().kotlin as KClass<out T>
这个函数调用java.lang.annotation.Annotation.annotationType()
我无法模拟扩展函数,因为 kotlin 将扩展函数转换为静态方法,而 Mockito 无法存根静态方法。
所以我直接嘲笑了java.lang.annotation.Annotation.annotationType()
。
这是我的新代码:
@Test
fun <T> supports_when_field_has_OneToOne_annotation_with_eager_fetch_type() {
val myHandler = MyHandler<T>()
val joinAnnotation = mock<OneToOne> {
on { this.fetch }.thenReturn(FetchType.EAGER)
on { (this as java.lang.annotation.Annotation).annotationType() }.thenReturn(OneToOne::class.java)
}
val supports = myHandler.supports(joinAnnotation)
assertThat(supports).isTrue()
}
有模拟静态方法的替代方法(PowerMock、MockK),但我没有测试。
如果谁有更好的建议,我很想看看