skip to content

MockK

MockK is the Kotlin-first mocking library, with a DSL that handles suspend functions, objects, and final classes that trip up Java-oriented mocking tools. If your project mocks anything, expect questions about it.

part ofKotlinoverview, primer and where to startread it →
on this pageshow

explore

questions

25

How do you create a mock with MockK and make one of its methods return a fixed value?

level: juniorimportance: must knowfreq 85%

answer

  1. mockk<T>() = create fake
  2. every { } returns = script return value
  3. strict by default: unstubbed call throws
  4. returnsMany / throws / answers terminators
  5. reified type param

basics

~10 s

Create the fake object with mockk(), then tell it what to return using every { obj.method() } returns value. After that, calling the method gives back the value you set.

solid answer

~40 s

Use the inline function mockk<T>() to create a mock of type T. By default it is a strict mock: every method must be stubbed or the call throws. You define behaviour with every { mock.method(args) } returns result. The lambda after every records which call to stub; returns supplies the canned value. Variants include returnsMany(listOf(...)) for sequential values, throws ex to raise an exception, and answers { ... } for dynamic logic using the call's arguments. Only non-final members are mockable by default; MockK uses bytecode manipulation (and an all-open-style agent) so final Kotlin methods also work via its inline mocking. You typically assign the mock to a val of the interface or class type and inject it into the class under test.

code

kotlin · 6 lines
kotlin
val repo = mockk<UserRepository>()
every { repo.findById(1L) } returns User(1L, "Ada")
every { repo.findById(2L) } returns null

assertEquals("Ada", repo.findById(1L)?.name)
assertNull(repo.findById(2L))

go deeper

for a junior

Can create mockk() and write a basic every { } returns and inject the mock.

for a middle

Knows strict vs relaxed default behaviour and the returnsMany/throws/answers terminators.

for a senior

Explains the reified type param, the recording DSL, and how bytecode/inline mocking handles final members.

for a principal

Reasons about when mocking is the right isolation tool vs fakes/real objects, and the maintenance cost of over-stubbing.

## What a mock is A *mock* is a fake implementation of a type, created at runtime, whose behaviour you script. You use it to isolate the *class under test* from its collaborators (databases, HTTP clients, other services). ## Creating a mock: `mockk<T>()` MockK's entry point is the inline reified function `mockk<T>()`. The `<T>` type parameter is `reified`, so MockK knows the concrete type at runtime and can generate a proxy. ```kotlin interface UserRepository { fun findById(id: Long): User? } val repo: UserRepository = mockk() // type inferred from the val // or val repo = mockk<UserRepository>() // explicit type argument ``` By default `mockk()` produces a **strict** mock: calling any method that has *not* been stubbed throws `MockKException`. (A *relaxed* mock that returns defaults is a separate feature — outside this topic.) ## Stubbing: `every { } returns` You script behaviour with the `every { }` block. Inside the lambda you write the exact call you want to intercept; the value after `returns` is what that call yields. ```kotlin every { repo.findById(1L) } returns User(1L, "Ada") ``` Key stubbing terminators: - `returns x` — return a single value every time. - `returnsMany(listOf(a, b, c))` — return a, then b, then c on successive calls. - `throws SomeException()` — throw instead of returning. - `answers { ... }` — compute the result dynamically; the lambda can read arguments via `firstArg()`, `secondArg()`, or `arg<T>(index)`. ```kotlin every { repo.findById(any()) } answers { User(firstArg(), "dynamic") } ``` ## How it works under the hood MockK uses bytecode manipulation. Because Kotlin classes and methods are `final` by default, MockK ships a JVM agent / inline mocking engine so it can stub even final members without you opening them. This is why `mockk()` works on most Kotlin types out of the box. ## Typical test shape ```kotlin @Test fun returnsUserName() { val repo = mockk<UserRepository>() every { repo.findById(1L) } returns User(1L, "Ada") val service = UserService(repo) assertEquals("Ada", service.nameOf(1L)) } ``` ## Gotchas - A strict mock throws on any unstubbed call — stub everything the test exercises. - The `every` lambda is a *recording* DSL, not a real invocation; don't put assertions there. - One `every` overrides a previous one for the same call signature.

  • What happens if you call a method on a strict mockk() that you never stubbed?
    It throws MockKException complaining there is no answer for that call. You must stub it or use a relaxed mock.
  • How would you make a stubbed method throw instead of return?
    Use every { mock.call() } throws SomeException() instead of returns.

every { } returns is like programming a vending machine: you tell it 'when someone presses B4, dispense this snack'.

saying these in an interview costs you the question

  • Thinking mockk() runs the real method body
  • Putting assertions inside the every { } lambda
  • Believing every call returns null/0 automatically (that's relaxed mocks)
  • Confusing every (stubbing) with verify (checking)
  • Claiming final Kotlin methods can't be mocked by MockK

context

open as a page

You have a mock with a suspend function and you write every { repo.load() } returns data — it won't compile. Why, and what do you use instead?

level: juniorimportance: must knowfreq 75%

basics

~10 s

every can only call ordinary functions. A suspend function must be called from a coroutine, so MockK gives you coEvery, which can run suspend calls inside its stub block. Use coEvery for suspend functions.

open as a page

In MockK, what does creating a mock with mockk<T>(relaxed = true) do, and how does it differ from a plain mockk<T>()?

level: juniorimportance: must knowfreq 70%

basics

~10 s

A relaxed mock auto-answers every call with a default value, so you don't have to stub each method. A plain mock throws if you call a method you never stubbed.

open as a page

How do you use mockkObject to stub a method on a Kotlin object (singleton) or companion object in a MockK test?

level: juniorimportance: must knowfreq 60%

basics

~10 s

Call mockkObject(MyObject) to turn the real singleton into a spy, then use every { MyObject.foo() } returns ... to fake a method. Clean up afterwards with unmockkObject or unmockkAll.

open as a page

In MockK, how do you assert that a mocked method was called a specific number of times, and what does verify { ... } default to when you don't pass a count?

level: juniorimportance: must knowfreq 70%

basics

~20 s

Use verify(exactly = n) { mock.method() } to require exactly n calls. A plain verify { ... } with no count means "at least one call" (atLeast = 1), so it fails only if the call never happened.

open as a page

How do you verify with MockK that a method was (or was not) called, and how many times?

level: middleimportance: must knowfreq 80%

basics

~20 s

Use verify { mock.method(args) } after the action to check the call happened. You can also pass exactly = n, atLeast, atMost, or exactly = 0 to assert how many times it ran or that it never ran.

open as a page

Walk through stubbing and verifying a suspend repository call in a runTest block. What's the difference between coVerify and verify, and what happens if you use the wrong one?

level: middleimportance: must knowfreq 70%

basics

~20 s

Use coEvery to stub the suspend call and coVerify to check it ran, all inside runTest. verify can't call a suspend function in its block, so it won't compile for suspend functions — you must use coVerify.

open as a page

What does spyk() create in MockK, and how does its behavior for unstubbed methods differ from a relaxed mock?

level: middleimportance: must knowfreq 60%

basics

~10 s

spyk() wraps a real object. Unstubbed methods run the real code and return real results. A relaxed mock never runs real code; unstubbed methods just return fake defaults.

open as a page

How does mockkStatic let you stub Kotlin top-level functions, extension functions, and Java static methods, and what do you pass to it?

level: middleimportance: must knowfreq 55%

basics

~10 s

mockkStatic tells MockK to intercept functions that have no instance — top-level functions, extension functions, and Java statics. You register the file/class, then stub with every { } and undo with unmockkStatic or unmockkAll.

open as a page

What is the difference between verifyOrder and verifySequence in MockK? When would each fail given a stream of recorded calls?

level: middleimportance: must knowfreq 60%

basics

~20 s

verifyOrder checks that the listed calls happened in that relative order, allowing other calls in between or around them. verifySequence is stricter: the listed calls must be the complete, exact, back-to-back list of all calls on those mocks, with nothing else.

open as a page

Why is teardown (unmockkObject/unmockkStatic/unmockkConstructor/unmockkAll) critical for object, static, and constructor mocks, and how do you guarantee it?

level: seniorimportance: must knowfreq 45%

basics

~20 s

Object, static, and constructor mocks change global JVM state shared by every test. If you don't undo them, the fake behavior leaks into later tests and causes flaky, order-dependent failures. Call unmockkAll in teardown to reset everything.

open as a page

Explain MockK argument matchers any() and eq(). When must you use a matcher, and what is the rule about mixing matchers with literals?

level: middleimportance: should knowfreq 65%

basics

~20 s

any() matches any argument; eq(x) matches a value equal to x. If you use a matcher for one argument in a call, you must use matchers for all arguments of that call — you can't mix matchers with plain values.

open as a page

When would you choose coAnswers over coEvery { } returns, and what does the answer block give you access to?

level: middleimportance: should knowfreq 50%

basics

~20 s

Use coAnswers when the stubbed suspend function needs dynamic behavior — computing a result from the arguments, suspending/delaying, or returning different values per call. returns gives a fixed value; coAnswers runs a suspend block each time.

open as a page

What is the difference between mockk(relaxed = true) and mockk(relaxUnitFun = true), and when would you choose relaxUnitFun?

level: middleimportance: should knowfreq 55%

basics

~10 s

relaxed = true auto-answers every method. relaxUnitFun = true only auto-answers methods that return Unit (void); methods that return a real value still throw unless you stub them.

open as a page

Explain verify(atLeast = n), verify(atMost = n), and how to assert a call count falls within a range in MockK. What happens if a verified call occurs more times than atMost allows?

level: middleimportance: should knowfreq 55%

basics

~20 s

atLeast = n requires n or more calls; atMost = n allows up to n. Combine them in one verify to assert a range. If calls exceed atMost, verification fails because too many matching invocations were recorded.

open as a page

How do slot() and capture() work in MockK, and when would you capture an argument instead of just matching it?

level: seniorimportance: should knowfreq 55%

basics

~10 s

A slot is a container. You pass capture(slot) where an argument goes, and MockK stores the real value the code passed in. Afterwards you read slot.captured to assert on or inspect that value.

open as a page

On a relaxed mock, you call a suspend function you never stubbed. What does it return, and how does this interact with coEvery and coVerify?

level: seniorimportance: should knowfreq 40%

basics

~20 s

A relaxed mock auto-returns a sensible default (0, false, empty, or a child relaxed mock) even for suspend functions, so unstubbed coEvery isn't required. You can still coEvery to override and coVerify to check calls.

open as a page

You're testing a service that depends on a collaborator with both void side-effect methods and value-returning methods. Walk through how you'd choose between strict mockk, relaxed = true, relaxUnitFun = true, and spyk, and the failure modes of each.

level: seniorimportance: should knowfreq 40%

basics

~20 s

Default to strict mockk and stub only what you read. Use relaxUnitFun for noisy void calls. Use relaxed only for collaborators you never read returns from. Use spyk when you want mostly real behavior with one method replaced.

open as a page

What does mockkConstructor do, and how do you stub and verify calls on instances created with `new` inside the code under test?

level: seniorimportance: should knowfreq 40%

basics

~10 s

mockkConstructor(MyClass::class) makes every future MyClass(...) produce a mock. You then stub with every { anyConstructed<MyClass>().foo() } returns ... and verify with verify { anyConstructed<MyClass>().foo() }.

open as a page

What do confirmVerified and excludeRecords do in MockK, and how do they combine to assert that no unexpected interactions occurred on a mock?

level: seniorimportance: should knowfreq 40%

basics

~20 s

confirmVerified(mock) asserts every recorded call on that mock was already verified — failing if any call went unchecked. excludeRecords removes uninteresting calls from the mock's recorded history so they don't trip confirmVerified or sequence checks.

open as a page

Given a dependency you need to fake, how do you choose between mockkObject, mockkStatic, mockkConstructor, and a plain mockk — and when would you refactor instead?

level: principalimportance: should knowfreq 35%

basics

~20 s

Use a plain mockk for normal injectable classes. Use mockkObject for Kotlin objects/companions, mockkStatic for top-level/extension/Java-static functions, and mockkConstructor for objects newed up internally. The heavier the tool, the more it hints you should refactor to inject the dependency instead.

open as a page

Compare returns, returnsMany, throws, and answers { } as stub terminators in MockK. When is answers { } the right choice?

level: seniorimportance: nice to knowfreq 45%

basics

~20 s

returns gives one fixed value, returnsMany gives values in sequence, throws makes the call fail, and answers { } computes the result with a lambda. Use answers when the return must depend on the call's arguments.

open as a page

How do you capture the argument passed to a suspend collaborator and verify the call within a deadline? Explain CapturingSlot with coVerify and the timeout option.

level: seniorimportance: nice to knowfreq 35%

basics

~20 s

Use a slot() with capture() in coEvery or coVerify to grab the actual argument, then assert on slot.captured. For async work, coVerify(timeout = ms) waits up to that many milliseconds for the call to happen before failing.

open as a page

When using spyk in MockK, why can stubbing a method fail to take effect for internal self-calls, and what does recordPrivateCalls do?

level: seniorimportance: nice to knowfreq 25%

basics

~20 s

A spy wraps a real object. When one real method calls another method on itself, that inner call often runs the real one and skips your stub. recordPrivateCalls = true lets MockK see and verify private method calls.

open as a page

Your team's interaction tests using verifySequence and confirmVerified keep breaking on benign refactors. How would you diagnose this and rework the verification strategy while keeping meaningful coverage?

level: principalimportance: nice to knowfreq 25%

basics

~20 s

Over-strict verifiers couple tests to incidental call order and noise. Reserve verifySequence/confirmVerified for true protocols; elsewhere use verify with counts or verifyOrder for the calls that matter, and excludeRecords to drop noise. Prefer state assertions over interaction assertions when possible.

open as a page