MockK: What It Is, Key Concepts and Syntax

Author: IT Sectr Published: 2026-04-08 Reading time: 8 min

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 — a Kotlin-oriented mocking library with support for coroutines and language features.
  • mockk() — the main method for creating a mock object, similar to Mockito.mock().
  • every { } — a block for configuring mock behavior (stubbing) in a declarative style.
  • coEvery / coVerify — special constructs for working with suspend functions in coroutines.
  • Relaxed mock — a mock that returns default values without explicit stubbing.

What Is MockK?

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.

How MockK Works

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.

Basic MockK Syntax

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.

kotlin
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)

Relaxed Mock: Less Boilerplate

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.

kotlin
// Relaxed mock — all methods return default values
val api = mockk<ApiService>(relaxed = true)

// No stubbing required — returns an empty list
println(api.getUsers()) // []

Creating Mocks and Relaxed Mocks

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.

FunctionTypeBehavior Without Stubbing
mockk()Strict mockThrows exception when an unstubbed method is called
mockk(relaxed = true)Relaxed mockReturns default value
spyk()SpyCalls the real method if no stub is configured
slot()Argument CaptorCaptures 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.

Stubbing: Configuring Behavior with the every Block

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.

Different Stubbing Methods

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).

kotlin
// 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 and coVerify for Coroutines

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.

Verifying Call Count

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 { }.

kotlin
// 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() }

Slot: Capturing Arguments

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.

kotlin
val userSlot = slot<User>()

verify { repo.save(capture(userSlot)) }

assertEquals("Alice", userSlot.captured.name)

MockK Annotations and JUnit Integration

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.

Example with MockKExtension

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.

kotlin
@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)
    }
}

MockK vs Mockito: Which to Choose for Kotlin

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.

CriterionMockKMockito
SyntaxKotlin DSL (every, verify)Java-style (when, thenReturn)
CoroutinescoEvery, coVerify (native)Requires additional libraries
Final classSupported by defaultRequires mockito-inline
KMPSupportedNot supported
Relaxed mockBuilt-inNo equivalent
PopularityGrowing in Kotlin communityDominates 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

How does a relaxed mock differ from a regular mock in MockK?

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.

How to mock extension functions in MockK?

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.

Does MockK work with Kotlin Multiplatform?

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.

How to verify call order in MockK?

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.

Can MockK and Mockito be used in the same project?

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

  • MockK — a Kotlin-first mocking library with native language support.
  • every { } — a declarative DSL for configuring mock behavior.
  • coEvery / coVerify — support for suspend functions in coroutines without additional dependencies.
  • Relaxed mock — a mock with default values that reduces boilerplate.
  • @MockK / @InjectMockKs — annotations for automatic mock creation in JUnit 5.
  • MockK vs Mockito — MockK is preferable for pure Kotlin projects and KMP.
  • verifySequence — verifying the strict order of method calls.

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.

Discuss the project

Read also