At this point, we spent a lot of time exploring MockK features and syntax, so at this point, adding coroutines will be trivial, trust me😉
Of course, you can find the rest of the series on my blog, too:
- Getting Started with MockK in Kotlin [1/5]
- Verification in MockK [2/5]
- MockK: Objects, Top-Level, and Extension Functions [3/5]
- MockK: Spies, Relaxed Mocks, and Partial Mocking [4/5]
- MockK with Coroutines [5/5]
Video Content
As always, if you prefer a video content, then please check out my latest YouTube video:
Additional Imports
As the first step, let’s add the necessary import:
testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.10.1")
This package provides utilities for testing coroutines.
And thanks to that, we can mock and test suspend functions.
Code To Test
Following, let’s introduce the suspended functions:
class Eight( private val one: EightOne, private val two: EightTwo, ) { suspend fun funToTest(): String { return "${one.returnInt()} ${two.returnString()}" } } class EightOne { suspend fun returnInt(): Int = 10 } class EightTwo { suspend fun returnString(): String = "Some String" }
And I know it does not make sense. But it is not important here😉
The important part is that we have suspended functions so we can start implementing tests.
MockK with Coroutines
As the next step, let’s try to implement the test “the old way”:
class EightTest { private val one: EightOne = mockk() private val two: EightTwo = mockk() private val eight = Eight(one, two) @Test fun `should return 1 codersee`() { every { one.returnInt() } returns 1 every { two.returnString() } returns "codersee" val result = eight.funToTest() assertEquals("1 codersee", result) verifySequence { one.returnInt() two.returnString() } } }
As a result, we can see the compiler complaining about our suspended functions:
Suspend function 'returnInt' should be called only from a coroutine or another suspend function Suspend function 'returnString' should be called only from a coroutine or another suspend function Suspend function 'funToTest' should be called only from a coroutine or another suspend function
So, as the first step, let’s add the runTest
to get rid of the last error:
@Test fun `should return 1 codersee`() = runTest {
The runTest
is not related to the MockK itself. It comes from kotlinx.coroutines
and executes our test body in a new coroutine, returning TestResult
.
When it comes to MockK, then we can work with coroutines and suspended functions by simply adding the “co” suffix for all functions:
class EightTest { private val one: EightOne = mockk() private val two: EightTwo = mockk() private val eight = Eight(one, two) @Test fun `should return 1 codersee`() = runTest { coEvery { one.returnInt() } returns 1 coEvery { two.returnString() } returns "codersee" val result = eight.funToTest() assertEquals("1 codersee", result) coVerifySequence { one.returnInt() two.returnString() } } }
And yes, this is that easy!😉
MockK comes with plenty of functions to work with suspend functions, like:
coVerify
coEvery
coJustRun
coJustAwait
coAnswers
- and many more😉
Issue With Spies
Lastly, at the moment of writing, there is one issue with spies and coroutines in MockK. You can see all the details here: https://github.com/mockk/mockk/issues/554
Assuming this is quite an old one, I wouldn’t expect it to be fixed in the near future.
But if that is the case, then please let me know in the comments below.
Summary
That’s all for this series about MockK – the mocking library for Kotlin.
During our time together, we learned A LOT, and I believe you are ready to use it in your projects!
Let me know your thoughts in the comments below, and if you are looking for the other articles, then here you are: