2

所以我有以下代码:

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案例之前重置该计数?
4

3 回答 3

6

这可能是因为 KotlinTest 在被视为测试的内容和Spec创建实例时与 JUnit 不同。

默认行为是为每次执行KotlinTest创建一个实例。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()
    }

}

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

于 2019-12-23T13:16:40.590 回答
2
  1. 您应该尝试提供的各种clear方法来重置模拟的状态。查看此相关问题MockK 的文档以获取更多信息。

  2. 检查有关测试侦听器的文档。基本上,每个测试规范类都提供了生命周期方法,例如beforeEach,您可以覆盖这些方法来重置您的模拟(使用clear)。当您扩展 BehaviourSpec 时,您应该能够只覆盖这些方法,否则请确认如何针对不同的测试样式执行此操作以避免混淆。

于 2019-12-23T08:26:02.520 回答
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()
}

例如,这适用于 a 中的每一片叶子WordSpec,并且也应该适用BehaviorSpec

于 2020-11-11T21:08:09.630 回答