eleven22
eleven22

Reputation: 93

Mockk verify wasNot called failed

I have a question regarding mockk.

When using MockK's wasNot called to check that ClassA is called, there is a problem that the test fails if it is called in another test even if ClassA is not called in the current test.

Why is this happening and how can I fix it?

Code:

class ClassA {
  fun method(): Int = 1
}

class ClassB(val classA: ClassA, var call: Boolean = true) {
  fun method(): Int = if(call) classA.method() else 0
}


class MyTest: FreeSpec({
  "Test" - {
    val mockClassA = mockk<ClassA>()
    val sut = ClassB(mockClassA)

    "methodA called" - {
      every { mockClassA.method() } returns 1

      sut.method()

      verify { mockClassA.method() }
    }

    "methodA not called" - {
      every { mockClassA.method() } returns 1
      sut.call = false

      sut.method()

      verify { mockClassA wasNot called } // failed here
    }
  }
})

Error message:

Verification failed: ClassA(#1) should not be called:

Upvotes: 1

Views: 1847

Answers (1)

Karsten Gabriel
Karsten Gabriel

Reputation: 3662

There are several ways how you can bypass that behavior.

Local mock

One way would be to just not reuse your mock, but instead create a new one, and and a new sut for each test. If this would lead to a lot of duplicated code, you can just write helper functions for the setup.

IsolationMode

You can define different Isolation Modes for your Kotest test. The default one is SingleInstance which means that there is one single spec instantiated when running the tests in your test class.

When you change this to InstancePerLeaf, then for every test leaf in your spec, a new spec instance is created. You can define that at different locations, for instance it the global ProjectConfig:

class ProjectConfig : AbstractProjectConfig() {
    override val isolationMode = IsolationMode.InstancePerLeaf
}

or locally for your test like this:

class MyTest : FreeSpec({
    isolationMode = IsolationMode.InstancePerLeaf
    "Test" - {
...

Clear mock

You can clear the internal state of each mock with clearMocks, or alternatively for all mocks with clearAllMocks. When you do this after each test, then the verification does not fail due to calls in earlier tests.

You can call it like this:

        "methodA called" - {
            every { mockClassA.method() } returns 1

            sut.method()

            verify { mockClassA.method() }
            clearMocks(mockClassA)
        }

or for all tests like this:

        afterAny {
            clearMocks(mockClassA)
        }
        "methodA called" - {
...

Upvotes: 1

Related Questions