Kotest 与 Mockk:如何清除验证计数

问题描述 投票:0回答:4

所以我有以下代码:

When("SMS with location update command is received") {
        every {
            context.getString(R.string.location_sms, any(), any(), any(), any())
        } returns "loc"
        mainServiceViewModel.handleSms(SmsMessage("123", "location"))

        Then("SMS with location is sent to specified phone number") {
            verify(exactly = 1) {
                smsRepository.sendSms("+123", "loc")
            }
        }
    }

    When("motion is detected") {

        Then("information SMS is sent to specified phone number") {
            verify(exactly = 1) {
                smsRepository.sendSms("+123", any())
            }
        }
    }

问题在于,尽管第二个案例没有执行任何操作,但两个案例都通过了。我预计第二种情况会失败,因为甚至没有调用 sendSms 方法。

  1. 如何重置smsRepository验证计数?
  2. 如何在每个 When 情况之前重置该计数?
kotlin unit-testing bdd mockk kotest
4个回答
7
投票

这可能是因为 Kotest 与 JUnit 在测试的定义以及创建

Spec
实例时有所不同。

Kotest
的默认行为是在每次执行时创建
Spec
的单个实例。因此,您的模拟不会在执行之间重置,因为您可能在
class level
创建了它们。


要解决此问题,您可以做的就是在测试中执行

mockk
,或者将 隔离模式 更改为每次执行测试时都会创建
Spec

默认

isolationMode
IsolationMode.SingleInstance
。您可以通过覆盖
Spec
函数来在
isolationMode
本身上更改它:

class MySpec : BehaviorSpec() {

    init {
        Given("XX") { 
            Then("YY") // ...
        }
    }

    override fun isolationMode() = IsolationMode.InstancePerTest

}

您也可以在 ProjectConfig 中更改它。如果您需要有关如何执行此操作的说明,请查看 ProjectConfig 上的文档


另一种方法是清除

afterTest
方法上的模拟:

class MySpec : BehaviorSpec() {

    init {
        Given("XX") { 
            Then("YY") // ...
        }
    }

    override fun afterTest(testCase: TestCase, result: TestResult) {
        clearAllMocks()
    }

}

但我不确定这在您的用例中如何工作。


2
投票
  1. 您应该尝试提供的各种

    clear
    方法来重置模拟的状态。检查此相关问题MockK的文档以获取更多信息。

  2. 查看有关测试监听器的文档。基本上,每个测试规范类都提供像

    beforeEach
    这样的生命周期方法,您可以重写这些方法来重置模拟(使用
    clear
    )。当您扩展 BehaviourSpec 时,您应该能够覆盖这些方法,否则请确认如何针对不同的测试样式执行此操作以避免混淆。


0
投票

要在每次测试后清除模拟,您可以提供项目范围的侦听器:

import io.kotest.core.listeners.TestListener
import io.kotest.core.spec.AutoScan
import io.kotest.core.test.TestCase
import io.kotest.core.test.TestResult
import io.mockk.clearAllMocks

@AutoScan
class MockkClearingTestListener : TestListener {
    override suspend fun afterEach(testCase: TestCase, result: TestResult) = clearAllMocks()
}

这有效,例如对于

WordSpec
中的每片叶子,也应该适用于
BehaviorSpec


0
投票

从 MockK 的 GitHub,您可以单独重置调用计数(或模拟行为的各种其他部分):

clearMocks(
    yourMockk,
    answers = false,
    recordedCalls = true,
    childMocks = false,
    verificationMarks = true,  // set this to true to have verifyAll be reset as well 
    exclusionRules = false
)

这里的关键是选择您想要重置的部分,并将它们作为

false
传递,因为
clearMocks
(和
clearAllMocks
)的行为是将它们中的每一个设置为true。因此,如果您想清除所有模拟的通话录音,但不想清除答案,您可以简单地调用:

clearAllMocks(answers=false)

© www.soinside.com 2019 - 2024. All rights reserved.