1. Overview
Kotlin has great compatibility with Java, but one difference is that Kotlin doesn’t contain the static modifier, and when it comes to mocking, Java static methods aren’t convenient to access. The mocking library Mockk has a feature that allows us to mock static Java methods easily.
In this tutorial, we’ll learn how to use this function and undo its effects after we’re done with it.
2. Using Mockk on a Java static Method
To set up our demonstration, let’s use RandomNumberGenerator as an example of a static Java class. We assume that this is whatever static method our external implementation gives us:
public class RandomNumberGenerator {
public static Double random() {
return Math.random();
}
}
Let’s use it in a simple example to determine the result of a coin flip based on the class we have created:
fun coinFlip() = if(RandomNumberGenerator.random() < 0.5) "heads" else "tails"
Some unit tests won’t require any change or mocking to work. Validating that our coin flip never throws an exception is an example of that:
@Test
fun `Doing a coin flip should not throw an exception`() {
repeat(1000) {
coinFlip()
}
}
In some other cases, however, we might want to assert the mechanisms behind our flip, which is the static random() method. For example, we may need to validate specific rules based on the result of the method call.
In our sample function, the assertion we want depends on an assumption: Whenever the static method is called, we’ll replace it with a class that returns what we want. The test should have a format similar to:
@Test
fun `Heads should be returned whenever RandomNumberGenerator returns less than 0,5`() {
// Simulate RandomNumberGenerator.random() returning a number < 0.5
assertEquals(coinFlip(), "heads")
}
To make sure we can control the returned value, let’s use mockkStatic() to fine-tune the result:
@Test
fun `Heads should be returned whenever random returns less than 0,5`() {
// Simulate RandomNumberGenerator.random() returning a number < 0.5
mockkStatic(RandomNumberGenerator::class)
every { RandomNumberGenerator.random() } returns 0.1
assertEquals(coinFlip(), "heads")
}
3. Removing a Mockk After Using It
We need to ensure we don’t mess with the static namespace we used, as many other methods might use the same static method. In other words, we don’t want our mocked behavior to leak into other tests. So, let’s unmock the static class we mocked previously:
@AfterEach
fun `Remove RandomNumberGenerator mockks`() {
unmockkStatic(RandomNumberGenerator::class)
}
4. Removing All Mockks at Once After Tests
We can also unmock what we’ve mocked after any test finishes running by using unmockkAll(). That limits the unmockk calls to a single place and ensures we won’t leak any modification to the rest of our test suite.
To do that, let’s add a method to our unit test class and annotate it with @AfterEach:
@AfterEach
fun `Remove all mocks`() {
unmockkAll()
}
5. Mocking Functions
Mocking top-level and extension functions in Kotlin can also be achieved using Mockk’s mockkStatic() function.
5.1. Mocking Top-Level Functions
A top-level function is explicitly declared directly in a file, and not enclosed within a class. At compile time, Kotlin generates an object class based on our file name and places our function in the object. Specifically, to mock this function, we need to statically mock the generated Kotlin class our top-level function lives in using that fully qualified class name with mockkStatic().
Let’s create topLevelFunction():
fun topLevelFunction(): String {
return "Hello, World!"
}
Now we’ll mock it with mockkStatic():
@Test
fun `mock top-level function`() {
mockkStatic("com.baeldung.mock.TopLevelFunctionKt")
every { topLevelFunction() } returns "Mocked Response"
assertEquals("Mocked Response", topLevelFunction())
unmockkStatic("com.baeldung.mock.TopLevelFunctionKt")
}
We mock the top-level function topLevelFunction() by calling mockkStatic() with the file’s fully qualified name. We use every() to specify the mocked return value. Finally, we verify that we get our mocked result with assertEquals() and clean up with unmockkStatic().
5.2. Mocking Extension Functions
Extension functions allow us to add new functionality to existing classes. Like before, the Kotlin compiler wraps our extension function in an object class derived from the file name.
Let’s define an extension function on String named greet():
fun String.greet(): String {
return "Hello, $this"
}
To mock this extension function, we’ll also use mockkStatic():
@Test
fun `mock extension function`() {
mockkStatic("com.baeldung.mockk.TopLevelExtensionKt")
every { "World".greet() } returns "Mocked Greeting"
assertEquals("Mocked Greeting", "World".greet())
unmockkStatic("com.baeldung.mockk.TopLevelExtensionKt")
}
We mock the String.greet() extension function using mockkStatic(). Again, we set the mock behavior with every(). Finally, we verify the result with assertEquals() and clean up with unmockkStatic().
6. Conclusion
In this article, we’ve learned how to use Mockk’s mockkStatic to mock static Java methods. We also prepared our test suite to unmockk any mocks we might have set up, ensuring we don’t pollute the context for other tests. Additionally, we explored how to mock top-level and extension functions.
As always, the implementation used in this article can be found over on GitHub.