Kotlin 测试利器—MockK

发表于:2020-10-13 09:31

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:嘻嘻z    来源:掘金

  为什么需要MockK
  在MockK之前,已经有一大批测试库可以用于Mocking,其中有名的也有很多,比如Mockito, PowerMock,Jmockit等等,但是他们都有各自的缺陷,这些缺陷也和Kotlin的特性有关。
  关键字
  在 Kotlin 裡面 when是关键字,Mockito 的when ,必须加上反引号才能使用:
`when`(xxxx).thenReturn(xxx)
  如果看起来不舒服,也可以舍弃 Mockito 改用 mockito-kotlin。
  在 mockito-kotlin中使用了whenever代替when,也有更简洁的写法,但是归根到底还是在使用Mockito的Api,所以功能上依然有局限性。
  Mock Kotlin的类时报错
org.mockito.exceptions.base.MockitoException: 
Cannot mock/spy class com.joetsai.kotlinunittest.token.TokenRepository
Mockito cannot mock/spy because :
 — final class
  这是因为Kotlin中类都是默认final类型,如果需要mock,则需要显示的加上open标识符,如果有100个类,则需要加100次,这也太麻烦了…
  静态方法如何Mock
  众所周知,Mockito是不支持静态方法的,如果想使用就需要使用PowerMock,但是PowerMock也有缺点。
  使用流程也比较繁琐
  Mockito与PowerMock是不同团队开发的,更新速度慢而且有兼容性问题。
  Jmockit
  完全与kotlin不兼容…
  MockK使用示例
  普通使用
fun test() {
    val mother = mockk<Mother>()
    every { mother.giveMoney() } returns 30 // when().thenReturn() in Mockito
    assertEquals(30, mother.giveMoney())
}
  mockkObject
object Son {
    fun test5(): Int {
        return 5
    }
}

mockkObject(Son)
every { Son.test5() } returns 10
assertEquals(10, Son.test5())
  mockkStatic
class Son {
    Static int test5() {
        return 5
    }
}   
@test
fun test() {
    mockkStatic(Son::class)
    every { Son.test5() } returns 10
    assertEquals(10, Son.test5())
}
  mock private method
class Son {
    public int publicResult() {
        return privateResult()
    }

    private int privateReuslt() {
        return 5
    }
}   
@test
fun test() {
    val son = mockk<Son>()
    every { son["privateResult"]() } returns 10
    assertEquals(10, son.publicResult())
}
  Context Mock
  在某些Android某些用户自定义的类中,需要Context才能初始化。
class Utils {
    public static void initialize(Context context) {
    instance = builder.build(context);
    }
    public static synchronized Utils getInstance() {
        if (instance == null) {
            throw new IllegalStateException("you must call initialize first");
        }
        return instance;
    }
}
  有两种初始化方式:
  直接mock context
val context = mockk<Context>()
Utils.init(context)
Utils.getInstance().xxxx()
  直接mock Util
val mockApplicationContext = mockk<Context>()
val utils = mockk<Utils.init>()
mockkStatic(Utils.init::class)
every { Utils.getInstance() } returns utils
every { utils.test() } returns null
......
  遇到的一些小坑
  从介绍来看,在mockStatic时只能mock非final类,所以如果mock系统自带的System类会直接报错。
  在Android instrument test时,需要设备Android版本>=9。
  在最新版(1.10.2)的MockK中,需要kotlin版本>=1.3.61
  最后
  因为当前项目是java和kotlin混编的,所以举得例子中也有不少java的demo。
  如果大家还有其他遇到的问题或者坑,欢迎留言。

  本文内容不用于商业目的,如涉及知识产权问题,请权利人联系51Testing小编(021-64471599-8017),我们将立即处理
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号