简体   繁体   中英

Kotlintest with Mockk How to clear verify count

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.

  1. How to reset smsRepository verify count?
  2. How to reset that count before every When case?

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.

  1. 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.

  2. 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM