So I have the following code:
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())
}
}
}
The problem with it, that both cases pass, even though the second one doesn't do any action. I expect second case to fail, as sendSms method is not even called.
This is probably due to the fact that KotlinTest is different from JUnit in what is considered a test and when a Spec
instance is created.
The default behavior for KotlinTest
is to create a single instance of the Spec
per execution. Due to this, your mocks are not getting reset between executions, as you probably have them created at class level
.
To fix this, what you can do is either do the mockk
inside the test, or change the isolation mode to something that creates the Spec
every time a test is executed.
The default isolationMode
is IsolationMode.SingleInstance
. You can change it on the Spec
itself by overriding the isolationMode
function:
class MySpec : BehaviorSpec() {
init {
Given("XX") {
Then("YY") // ...
}
}
override fun isolationMode() = IsolationMode.InstancePerTest
}
You can also change it in a ProjectConfig. If you need explanation on how to do it there, check the docs on ProjectConfig
An alternative would be to clear mocks on the afterTest
method:
class MySpec : BehaviorSpec() {
init {
Given("XX") {
Then("YY") // ...
}
}
override fun afterTest(testCase: TestCase, result: TestResult) {
clearAllMocks()
}
}
But I'm not sure how that would work in your use-case.
You should try the various clear
methods that are provided to reset the state of mocks. Check this related question and MockK's docs for more information.
Check the documentation about test listeners . Basically, every test spec class provides lifecycle methods like beforeEach
, which you could override to reset your mocks (using clear
). As you are extending BehaviourSpec, you should be able to just override those methods, otherwise confirm how to do this for different testing styles to avoid confusion.
To clear mocks after every test, you can provide a project wide listener:
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()
}
This works eg for every leaf in a WordSpec
, and should work for BehaviorSpec
as well.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.