Mockito mock Kotlin Object类方法报错解决方法
作者:穹柏 时间:2022-03-10 15:23:37
比如我创建一个Kotlin
Object
类:ObjectMethod
package com.baichuan.example.unit_test
object ObjectMethod {
fun doSomething() {
println("this is ObjectMethod#doSomething")
}
@JvmStatic
fun doSomethingWithJvmStatic() {
println("this is ObjectMethod#doSomethingWithJvmStatic")
}
}
如果我直接去mock
该类的doSomething
方法,会报错。
@Test
@DisplayName("mock普通的kotlin静态方法")
fun testMockKotlinObject() {
Assertions.assertThrows(MissingMethodInvocationException::class.java) {
Mockito.mockStatic(ObjectMethod::class.java).`when`<Unit>(
ObjectMethod::doSomething
).thenAnswer { println("this is mocked Object#doSomething") }
}
ObjectMethod.doSomething()
}
这是因为kotlin
里的object
类里的方法虽然在kotlin
里从形态跟使用上来看与静态方法无二。但是编译成java
代码后,其本质其实是内部初始化了一个当前类的静态常量实例INSTANCE
。这个INSTANCE
在kotlin
语法里被隐藏了,但在java里依然可以显示访问。ObjectMethod
编译成java
后的代码如下:
public final class ObjectMethod {
@NotNull
public static final ObjectMethod INSTANCE = new ObjectMethod();
private ObjectMethod() {
}
public final void doSomething() {
String var1 = "this is ObjectMethod#doSomething";
boolean var2 = false;
System.out.println(var1);
}
@JvmStatic
public static final void doSomethingWithJvmStatic() {
String var0 = "this is ObjectMethod#doSomethingWithJvmStatic";
boolean var1 = false;
System.out.println(var0);
}
}
所以,不能mock
ObjectMethod#doSomething
本质上的原因是正常手段无法mock
静态常量。如果想要使kotlin
的object
类中的方法能够被mock
,只需在方法上加上@JvmStatic
注解即可。被其标注的方法会被编译成普通的java
静态方法。
上面说正常手段无法mock静态常量,那么非正常手段呢?其实这个非正常手段就是通过反射将被mock
过的实例注入到ObjectMethod
中即可。
@Test
@DisplayName("通过反射修改静态常量来mock普通的kotlin静态方法")
fun testMockKotlinObjectMethodByReflection() {
val mock = Mockito.mock(ObjectMethod::class.java)
Mockito.`when`(mock.doSomething()).then {
print("this is mocked ObjectMethod by reflection")
}
val declaredMethod = ObjectMethod::class.java.getDeclaredField("INSTANCE")
ReflectionUtils.setFinalStatic(declaredMethod, mock)
ObjectMethod.doSomething()
}
ReflectionUtils
package com.baichuan.example.unit_test
import java.lang.reflect.Field
import java.lang.reflect.Modifier
object ReflectionUtils {
@Throws(Exception::class)
fun setFinalStatic(field: Field, newValue: Any) {
field.isAccessible = true
val modifiersField: Field = Field::class.java.getDeclaredField("modifiers")
modifiersField.isAccessible = true
modifiersField.setInt(field, field.modifiers and Modifier.FINAL.inv())
field.set(null, newValue)
}
}
github
https://github.com/scientificCommunity/blog-sample/tree/main/unit-test-sample
来源:https://blog.csdn.net/scientificCommunity/article/details/120258224
标签:Kotlin,Object
0
投稿
猜你喜欢
springcloud之自定义简易消费服务组件
2022-01-29 00:18:24
关于Java中BeanMap进行对象与Map的相互转换问题
2023-09-18 07:25:36
简单了解Spring beanfactory循环依赖命名重复属性
2023-10-27 19:39:14
idea输入sout无法自动补全System.out.println()的问题
2023-11-28 21:34:03
详解SpringBoot 快速整合Mybatis(去XML化+注解进阶)
2022-02-19 03:54:29
Java读文件修改默认换行符的实现
2023-11-29 08:24:32
DevExpress之ChartControl实现柱状图演示实例
2023-05-27 08:45:15
Java mybatis 开发自定义插件
2022-11-26 03:29:24
java获取当前时间并格式化代码实例
2021-10-06 17:06:16
Spark SQL的自定义函数UDF使用
2022-07-31 04:19:47
SpringBoot SSO轻松实现(附demo)
2022-04-05 02:24:33
一篇文章掌握Java Thread的类及其常见方法
2023-03-11 09:43:03
Springboot中如何使用Jackson
2021-07-29 03:27:34
java通过AES生成公钥加密数据ECC加密公钥
2023-08-04 10:09:53
Spring整合junit的配置过程图解
2022-12-18 16:37:48
详解Kotlin:forEach也能break和continue
2022-05-03 01:24:10
MyBatis-Plus找不到Mapper.xml文件的几种解决方法
2023-11-24 03:37:52
Java-JFrame窗体美化方式
2022-08-17 10:07:38
JAVA实现红包分发的示例代码
2022-10-08 06:18:15
Java实现SSL双向认证的方法
2023-09-22 10:34:35