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

SMG*_*ost 9 bdd unit-testing kotlin mockk kotest

所以我有以下代码:

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())
            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

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

  1. 如何重置 smsRepository 验证计数?
  2. 如何在每个 When 情况之前重置该计数?

Ker*_*ker 7

这可能是因为 Kotest 与 JUnit 在测试的定义和实例的Spec创建时间上有所不同。

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


要解决此问题,您可以做的就是在mockk测试内部进行,或者将隔离模式更改为每次执行测试时都会创建的隔离模式。Spec

默认isolationModeIsolationMode.SingleInstance. Spec您可以通过覆盖该函数来更改它本身isolationMode

class MySpec : BehaviorSpec() {

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

    override fun isolationMode() = IsolationMode.InstancePerTest

}
Run Code Online (Sandbox Code Playgroud)

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


另一种方法是清除该afterTest方法的模拟:

class MySpec : BehaviorSpec() {

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

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

}
Run Code Online (Sandbox Code Playgroud)

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