Mockito mock Kotlin Object类方法报错 Mockito mock Kotlin Object类方法报错解决办法
穹柏 人气:0想了解Mockito mock Kotlin Object类方法报错解决办法的相关内容吗,穹柏在本文为您仔细讲解Mockito mock Kotlin Object类方法报错的相关知识和一些Code实例,欢迎阅读和指正,我们先划重点:Mockito,mock,Kotlin,Object类方法,Mockito,mock,Kotlin,Object类方法报错,下面大家一起来学习吧。
比如我创建一个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
加载全部内容