1. Overview
In unit testing with MockK, a popular mocking framework for Kotlin, we often need to manage the lifecycle of our mocks effectively. Two key functions for this purpose are clearAllMocks() and unmockkAll(). Both play crucial roles in maintaining the integrity of our tests, but they serve distinct purposes.
In this tutorial, let’s explore the differences between these two functions and understand when to use each one.
2. Regular Mock Objects
First, let’s see how the clearAllMocks() and unmockkAll() functions work with regular mocks.
Let’s say we have a class:
class GreetingService {
fun greeting(name: String) = "$name, how are you?"
}
As the example shows, the GreetingService class has one function: greeting().
In tests, *we can get a mock object of GreetingService and stub the greeting() function using mockk():*
val greetingServiceMock = mockk<GreetingService> {
every { greeting(any()) } returns "mocked instance"
}
assertEquals("mocked instance", greetingServiceMock.greeting("Kai"))
The test shows that the stub is on duty. Calling greeting() with “Kai” returns the desired result.
Next, let’s test what clearAllMocks() does:
clearAllMocks()
assertThrows<MockKException> {
greetingServiceMock.greeting("Kai")
}.also { it.message?.startsWith("no answer found for: com.baeldung.mockk.GreetingService") }
As we can see in the test above, after clearAllMocks(), calling greeting() raises an exception. This is because clearAllMocks() removes all stubs on all mocks.
However, if we call unmockkAll() instead of clearAllMocks(), it may surprise us:
unmockkAll()
assertEquals("mocked instance", greetingServiceMock.greeting("Kai"))
As we can see, *after unmockkAll(), the mock object and the stub are still available*. In other words, unlike the function name implies, the mock isn’t “un-mocked”. This is because unmockkAll() is designed for un-mocking static mocks, Kotlin object mocks, top-level function mocks, and so on. It doesn’t clean or remove mocks of regular classes.
Next, let’s examine the difference between clearAllMocks() and unmockkAll() when they work on these kinds of mocks.
3. Mocks Created by mockkStatic() and mockkObject()
Let’s first create some examples so that we can easily demonstrate the usage of clearAllMocks() and unmockkAll():
class GreetingService {
... // fun greeting()
companion object {
fun sayGoodDay(name: String) = "$name, good day!"
}
}
We extend the GreetingService class by adding a companion object with the sayGoodDay() function. The sayGoodDay() function is quite similar to Java’s static method. We’ll stub this function later.
In Kotlin, an object represents a single static instance of a type. Next, let’s create an object with a function:
object GoodMorning {
fun sayGoodMorning(name: String) = "$name, good morning!"
}
Finally, let’s also create a top-level function:
fun sayGoodNight(name: String) = "$name, good night!"
The sayGoodNight() function isn’t declared in any classes. Instead, it’s defined at the top level of a kt file.
3.1. Mocking and Stubbing
*Mockk provides the convenient mockkObject() function to mock companion objects, objects*. To mock top-level functions, mockkStatic() is the function we should use.
Next, let’s mock the examples we created and stub the functions:
mockkObject(GreetingService)
every { GreetingService.sayGoodDay(any()) } returns "mocked static fun"
assertEquals("mocked static fun", GreetingService.sayGoodDay("Kai"))
mockkObject(GoodMorning)
every { GoodMorning.sayGoodMorning(any()) } returns "mocked object"
assertEquals("mocked object", GoodMorning.sayGoodMorning("Kai"))
mockkStatic(::sayGoodNight)
every { sayGoodNight(any()) } returns "mocked top-level fun"
assertEquals("mocked top-level fun", sayGoodNight("Kai"))
Next, let’s see what happens to these mocks if we call clearAllMocks() and unmockkAll() based on this test code.
3.2. Calling clearAllMocks() and unmockkAll()
Let’s first examine the effect after calling the clearAllMocks() function:
... // mocking and stubbing
clearAllMocks()
assertEquals("Kai, good day!", GreetingService.sayGoodDay("Kai"))
assertEquals("Kai, good morning!", GoodMorning.sayGoodMorning("Kai"))
assertEquals("Kai, good night!", sayGoodNight("Kai"))
As the test shows, after clearAllMocks(), no matter whether companion object mocks, object mocks, or top-level function mocks, internal states associated with the mock object are removed, such as stubs. Therefore, when we call those functions again, the actual functions are executed.
Next, let’s check how unmockkAll() affects the mocks:
... // mocking and stubbing
unmockkAll()
assertEquals("Kai, good day!", GreetingService.sayGoodDay("Kai"))
assertEquals("Kai, good morning!", GoodMorning.sayGoodMorning("Kai"))
assertEquals("Kai, good night!", sayGoodNight("Kai"))
As we can see, after calling unmockkAll(), the stubs no longer work; the actual functions are invoked. It looks the same as calling clearAllMocks().
However, these two functions have significant differences.
3.3. Differences
We noted earlier that the clearAllMocks() function resets the state of all mocks. On the other hand, unmockkAll() not only resets mocks’ state but also removes mock instances. In other words, after calling unmockkAll(), the mocks are no longer available for further interactions unless recreated.
Next, let’s take the top-level function sayGoodNight() as an example to demonstrate this difference:
mockkStatic(::sayGoodNight)
every { sayGoodNight(any()) } returns "mocked top-level fun"
assertEquals("mocked top-level fun", sayGoodNight("Kai"))
clearAllMocks()
assertEquals("Kai, good night!", sayGoodNight("Kai"))
every { sayGoodNight(any()) } returns "get mocked again"
assertEquals("get mocked again", sayGoodNight("Kai"))
In this example, clearAllMocks() clears the mock state. Then, if we want to re-stub the function using every { … } returns …, we can reuse the mock object.
However, if we replace clearAllMocks() with unmockkAll(), we cannot reuse the mock object, since it has been removed. Let’s create another test to verify it:
mockkStatic(::sayGoodNight)
every { sayGoodNight(any()) } returns "mocked top-level fun"
assertEquals("mocked top-level fun", sayGoodNight("Kai"))
unmockkAll()
assertEquals("Kai, good night!", sayGoodNight("Kai"))
assertThrows<MockKException> {
every { sayGoodNight(any()) } returns "mocked again"
}.also { it.message?.startsWith("Failed matching mocking signature") }
The above code shows that *if we try to re-stub the function after calling unmockkAll(), the MockKException will be raised*.
We must re-mock the top-level function using mockkStatic() to create a new stub:
mockkStatic(::sayGoodNight)
every { sayGoodNight(any()) } returns "mocked again"
assertEquals("mocked again", sayGoodNight("Kai"))
In this example, re-mocking is required as unmockkAll() removed all mock objects.
4. When to Use Each Function
We’ve explored the similarities and differences between Mockk’s cleanAllMocks() and unmockkAll(). Now, let’s summarize “when to use each” in a table so that we can have a better overview:
Regular mocks
Static / Companion object / Top-level function mocks
cleanAllMocks()
Clear all mocks’ states
Reset the state of mocks between tests but retain the mock instances for reuse.
Ideal for maintaining test isolation while allowing shared mock instances.
unmockAll()
No effects
Completely clean up all mocks.
Suitable when we want to ensure that no mocks persist beyond the current set of tests, preventing any potential interference with other test suites.
5. Conclusion
Both clearAllMocks() and unmockkAll() are valuable tools in the MockK framework. In this article, we’ve explored their similarities and differences through examples and discussed which function is appropriate for which situation.
As always, the complete source code for the examples is available over on GitHub.