MockK is a Kotlin-first mocking framework designed specifically for the Kotlin ecosystem, taking into account its language features: coroutines, extension functions, data classes, and sealed classes. Unlike Mockito, which was ported to Kotlin from Java, MockK was originally designed for Kotlin syntax and does not require additional plugins to work with final classes. According to MockK.io, the library is used in more than 40% of Kotlin projects with unit testing.
Key Takeaways
MockK is a library for creating mock objects, written in Kotlin and optimized for its syntax. It solves the same problems as Mockito — isolating tested code from dependencies — but does so using Kotlin-specific constructs: lambdas, DSL, reified generics, and suspend functions.
The main advantage of MockK over ported solutions is native Kotlin support. In Mockito, mocking a final class requires opt-in (mockito-inline), and static methods require mockStatic. MockK supports this by default, since Kotlin classes are final by default, and bypassing this limitation is built into the library's architecture.
Version 1.13.12 (2024) is a stable release supporting Kotlin 2.0, the K2 compiler, and multiplatform projects (KMP). MockK also works with Kotlin/Native and Kotlin/JS, making it the only choice for KMP projects where neither Mockito nor EasyMock are applicable.
MockK is designed with Kotlin's specifics in mind and uses language features — reified generics, DSL with lambdas, inline functions — to provide a concise and type-safe API without sacrificing performance.
The mechanism of MockK is based on bytecode instrumentation via the ByteBuddy library (like Mockito), but wraps it in a Kotlin-friendly DSL. Instead of when().thenReturn() chains, MockK uses lambda blocks every { } and coEvery { } that look like a natural language extension. Under the hood, MockK intercepts the call inside the lambda, analyzes the method and arguments through reflection, and matches them against recorded stubbing rules.
The block every { mock.method() } returns value reads as “every time the method is called, return the value.” This declarative syntax is closer to Kotlin style and eliminates confusion with argument order in when(). Thanks to Kotlin's reified generics, the mock type is inferred automatically without explicitly specifying the class.
val repository = mockk<UserRepository>()
// Stubbing: each call to findById(1) returns the user
every { repository.findById(1) } returns User("Alice")
// Call and verification
val result = repository.findById(1)
assertEquals("Alice", result.name)
Unlike Mockito, where each method must be configured explicitly, MockK supports relaxed mock — a mock that returns “reasonable” default values for any method: an empty list for List, 0 for Int, an empty string for String. This drastically reduces the amount of setup code.
// Relaxed mock — all methods return default values
val api = mockk<ApiService>(relaxed = true)
// No stubbing required — returns an empty list
println(api.getUsers()) // []
MockK offers several ways to create mock objects: mockk<T>() for strict mocks (each method must be explicitly configured), mockk<T>(relaxed = true) for relaxed mocks, and spyk(obj) for creating a spy on a real object.
| Function | Type | Behavior Without Stubbing |
|---|---|---|
| mockk() | Strict mock | Throws exception when an unstubbed method is called |
| mockk(relaxed = true) | Relaxed mock | Returns default value |
| spyk() | Spy | Calls the real method if no stub is configured |
| slot() | Argument Captor | Captures the argument for verification |
The choice between strict and relaxed mock depends on the context. A strict mock ensures that the test does not use methods whose behavior is undefined — this increases reliability. A relaxed mock is convenient for quick test prototyping where not all dependencies matter. In practice, it is recommended to start with a strict mock and switch to relaxed only when stubbing takes more lines than the test itself.
The every block is the central stubbing construct in MockK. Inside the lambda, a method call with specific arguments is described, and then a value is returned via returns, an exception is thrown via throws, or a response is computed via answers.
MockK supports all scenarios needed for testing: returning a value, throwing an exception, computing a response based on arguments, and multiple answers in order (call sequence).
// Return value
every { repo.findById(1) } returns User("Alice")
// Throw exception
every { repo.findById(999) } throws NotFoundException()
// Dynamic answer
every { repo.save(any()) } answers {
val user = firstArg<User>()
user.copy(id = 42)
}
// Answer sequence
every { repo.findAll() } returnsMany listOf(
listOf(User("Alice")),
listOf(User("Bob")),
emptyList()
)
Verify in MockK is similar to Mockito.verify() in purpose, but uses Kotlin DSL: verify { mock.method() }. For suspend functions, coVerify { mock.suspendMethod() } is used, which works correctly with coroutines and does not require a special runner.
MockK supports the same modifiers as Mockito: exactly(1), atLeast(2), atMost(5), wasNot(Called). The syntax is minimal — the modifier is passed as the first argument in verify { }.
// Verify: method called exactly 1 time
verify(exactly = 1) { repo.save(any()) }
// Verify call order
verifySequence {
repo.save(any())
repo.flush()
}
// coVerify for suspend functions
coVerify { api.fetchUsers() }
For argument verification, slot() is used — an analog of ArgumentCaptor. A slot is declared before the call, passed into every or verify, and after the test execution contains the captured value.
val userSlot = slot<User>()
verify { repo.save(capture(userSlot)) }
assertEquals("Alice", userSlot.captured.name)
MockK provides the @MockK and @RelaxedMockK annotations for creating mocks via initialization in JUnit 5. The MockKExtension automatically creates mocks before each test and cleans up afterward — similar to MockitoExtension, but with relaxed mode support.
The @InjectMockKs annotation (or the alternative @MockK with explicit object creation) injects mocks into the test instance. This reduces boilerplate and makes the test code cleaner.
@ExtendWith(MockKExtension::class)
class UserServiceTest {
@MockK
lateinit var repository: UserRepository
@InjectMockKs
lateinit var service: UserService
@Test
fun `getUser returns user from repository`() {
every { repository.findById(1) } returns User("Alice")
assertEquals("Alice", service.getUser(1)?.name)
}
}
The choice between MockK and Mockito depends on the team composition and project type. Mockito has a larger ecosystem, more examples, and more integrations, but MockK provides cleaner Kotlin syntax and native support for language features. For new Kotlin projects, MockK is recommended as the more idiomatic solution.
| Criterion | MockK | Mockito |
|---|---|---|
| Syntax | Kotlin DSL (every, verify) | Java-style (when, thenReturn) |
| Coroutines | coEvery, coVerify (native) | Requires additional libraries |
| Final class | Supported by default | Requires mockito-inline |
| KMP | Supported | Not supported |
| Relaxed mock | Built-in | No equivalent |
| Popularity | Growing in Kotlin community | Dominates in Java and hybrid projects |
For pure Kotlin projects (without Java classes), MockK is preferable: less boilerplate, native coroutine support, no surprises with final classes. For hybrid projects or teams with a Java background, Mockito remains a working option — both libraries can be used in the same project through different modules. When migrating from Mockito to MockK, it is enough to replace @Mock annotations with @MockK and rewrite when().thenReturn() blocks into the every { } format.
Frequently Asked Questions
Relaxed mock returns default values for all unstubbed methods (empty list, 0, null) without throwing exceptions. A regular (strict) mock requires explicit stubbing of each method — otherwise the test fails. Relaxed mock is convenient for quick tests, strict is for reliable ones.
MockK supports mocking extension functions via mockkStatic(). This is possible because extension functions in Kotlin are static methods with the receiver as the first parameter. For each extension function, you need to specify the class in which it is declared.
Yes, MockK supports Kotlin Multiplatform (KMP) for common code. On JVM, Native, and JS platforms, you can use the common API: mockk(), every, verify. This makes MockK the only choice for KMP projects where Mockito does not work.
Use verifySequence { } — a block where calls are specified strictly in the expected order. If the actual order differs, verifySequence will throw an exception indicating the first mismatched call.
Yes, technically it is possible, but not recommended. Conflicts may occur at the bytecode instrumentation level (ByteBuddy vs mockito-inline). If a project already uses Mockito, migration to MockK can be gradual through module isolation.
Summary
We will develop a mobile application turnkey
IT Sectr creates iOS and Android applications for startups and businesses since 2017. We will advise you and propose the best solution.
Read also