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。这个INSTANCEkotlin语法里被隐藏了,但在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静态常量。如果想要使kotlinobject类中的方法能够被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
  • asp之家 软件编程 m.aspxhome.com