MockK正式上场,似曾相识的场景

其实在程序考试结束後,连接着两人关系的补课也该跟着结束了。

但是诗忆彷佛没注意到这点似的,带着早就准备好的甜食等在门口,看到最後一个考生离开马上跑进教室。

「学姐!」

「嗯?」唯心本来正在擦拭白板,听到声音便偏过头来看。

「学姐也累了吧?我这里有饼乾和糖果唷。」

「系计中教室里禁止饮食唷。」

「啊,不小心忘记了,那,等学姐出来再一起吃吧。」诗忆把食物收回包里。

「好唷,我快收拾完了,对了,我听说你对MockK有兴趣?」

「咦?学姐怎麽知道的?」

「当然是有人告诉我的呀。」唯心看了一下旁边开着的电脑。「要不然我们先稍微研究一下再吃东西吧。」

打开MockK官网的网址和IDE,唯心注意到有版本搭配的说明。

From version 1.10.0 MockK does not support Kotlin 1.2.*,所以先检查一下我们现在使用的kotlin版本吧。」於是乘载函式库资讯的build.gradle.kts再次受到关注。

plugins {
    kotlin("jvm") version "1.5.10"
}

「是1.5.10。」诗忆说。

「对呀,那我们就可以安心使用1.10.0後的最新版本了。」唯心说着,就把函式库连着变数直接黏贴上去。

dependencies {
//...
    testImplementation("io.mockk:mockk:{version}")
}

「学姐,稍等一下,我记得最新版本号在官网上面。」诗忆想要先离开IDE画面。

「啊,不用那麽麻烦,来,我教你用IDE拿最新版本的方法。」唯心点击IDE下方的Dependencies。

图1

打开了函式库管理列表,点击MockK的那列,选了版本表最上方的1.12.0。

图2
图3

build.gradle.kts里的函式库的版本号变数也自动替换上被选择的版本。

dependencies {
//...
    testImplementation("io.mockk:mockk:1.12.0")
}

「好了,那我们来看看官网的范例吧,毕竟这麽多函式不可能每个都试一遍呀。」唯心笑笑。

图4

val car = mockk<Car>()

every { car.drive(Direction.NORTH) } returns Outcome.OK

car.drive(Direction.NORTH) // returns OK

verify { car.drive(Direction.NORTH) }

confirmVerified(car)

她看完范例後,很快就有了思路。「我觉得我们可以继续用之前的饮料例子唷。」

class Drink(val name: String, val price: Int) {//饮料类别
    fun freeAdd(): Boolean {//是否免费加料
       return true 
    }
}

class DrinkOrder(private val drink: Drink) {//饮料订单类别
    var price = drink.price
    fun add() {//加料
       if (!drink.freeAdd()) {
           price += 10
       }
    }
}

准备好饮料类别和饮料订单类别後,唯心着手写新测试。

import io.mockk.*
import kotlin.test.Test
import kotlin.test.assertEquals

class DrinkOrderTest {
    @Test
    fun add() {
        val drink = mockk<Drink>()
        every { drink.price } returns 60
        every { drink.freeAdd() } returns false
        val order = DrinkOrder(drink)
    }
}

「咦?所以我们不用真的写一个Drink物件,本来还在想饮料订单类别不需要饮料名字,还要想饮料名字有点麻烦的。」诗忆睁大眼睛。

「是呀,因为饮料订单依赖着外部传入的饮料物件,所以要用mockk<T>(...)的泛型概念建立饮料的假物件,不是本尊唷。接着用every假造必要的函式和变数的回传,就可以在饮料订单里帮饮料加料了。针对外部物件的假造,我记得是用Stub来称呼,但测试的主角是饮料订单呢,所以接下来要验证饮料订单加料的结果。」

@Test
    fun add() {
        val drink = mockk<Drink>()
        every { drink.price } returns 60
        every { drink.freeAdd() } returns false
        val order = DrinkOrder(drink)

        order.add()
        verify{ drink.freeAdd() }
        assertEquals(60, order.price)
}

「为什麽要verify函式drink.freeAdd()呢?」

「喔,是为了确定前面的执行过程中有没有呼叫到这个函式呀,因为order.add()的前提条件需要drink.freeAdd()。顺带一提,every的位置很重要唷,如果你没提供饮料资料就投进饮料订单,会出现错误唷。」

class DrinkOrderTest {
    @Test
    fun add() {
        val drink = mockk<Drink>()
        val order = DrinkOrder(drink)
        every { drink.price } returns 60
        every { drink.freeAdd() } returns false
    }
}

出现错误no answer found for: Drink(#1).getPrice()。因为DrinkOrder初始化所要取得drink.price的值就是呼叫drink.getPrice()

class DrinkOrderTest {
    @Test
    fun add() {
        val drink = mockk<Drink>()
        every { drink.price } returns 60
        val order = DrinkOrder(drink)
        every { drink.freeAdd() } returns false
        order.add()
        verify{ drink.freeAdd() }
        assertEquals(60, order.price)
    }
}

「学姐,范例里还有confirmVerified,你没加进去呢。」

「嗯⋯⋯其实那是用来确认是不是验证过所有的函式,没验证的会出现在Not verified calls清单里。顺带一提,只能验证mock的对象,也就是说,我们只能confirmVerified(drink),不能confirmVerified(order),後者会出现错误can't find stub DrinkOrder@137ceb57。」

「学姐,既然范例都说完了,我们可以去吃点心了吧。」诗忆觉得她的大脑和肠胃正在一同发出抗议。

「喔,差点都忘记这回事了呢,我们走吧。」唯心转身提起包,却没留意到旁边有个被留在桌上的水杯。

杯里的水,洒了出来。

急忙伸出手试图阻止水往电脑溅的诗忆,突然脑海中有什麽闪过,感觉眼前的场景好像在以前也发生过。


<<:  Day19-Flex属性_超简单制作导览列

>>:  Day19-706. Design HashMap

D7(9/7)-91App(6741) 帮商家做电商的电商专家

注:发文日和截图的日期不一定是同一天,所以价格计算上和当日不同,是很正常的。 声明:这一系列文章并无...

30-9 之Presentation Layer - MVP ( Model-View-Presenter )

接下来我们来谈谈 MVP ( Model-View-Presenter ),在知道 MVC 也只是在...

Day 29 - WooCommerce: 接收虚拟帐号付款成功通知

今天铁人赛的倒数第一天了 ^^,要和大家分享的是,如何接收永丰银行丰收款金流平台收到顾客的银行转帐汇...

Day07:文件

有哪些文件:orientation. 技术、API、测试等 自动化产生,自动化建置流程的一部分 新...

Day5-TypeScript(TS)宣告

今天要进入程序码的部分了。 我会以JavaScript(JS)为基础做比较与解释, 同时也了解两者在...