所以我有以下代码:
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 方法。
这可能是因为 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()
}
}
但我不确定这在您的用例中如何工作。
您应该尝试提供的各种
clear
方法来重置模拟的状态。检查此相关问题和MockK的文档以获取更多信息。查看有关测试监听器的文档。基本上,每个测试规范类都提供像
beforeEach
这样的生命周期方法,您可以重写这些方法来重置模拟(使用 clear
)。当您扩展 BehaviourSpec 时,您应该能够覆盖这些方法,否则请确认如何针对不同的测试样式执行此操作以避免混淆。要在每次测试后清除模拟,您可以提供项目范围的侦听器:
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
。
从 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)