skip to content

A Kotlin test fails with `io.mockk.MockKException: Missing calls inside every { ... } block.` What does MockK mean by that, and how would you diagnose it systematically?

level: seniorimportance: should knowfreq 35%

answer

  1. empty recording, not a matching failure
  2. is the receiver actually a mock?
  3. top-level/extension = static dispatch, never reaches the mock
  4. chained call needs a mock in the middle
  5. triage: Missing calls vs Failed matching vs no answer found

basics

~20 s

It means MockK's recorder saw no mockable call inside the block. Usually the target is not a mock, the call was resolved statically (top-level or extension function, an unmocked static), it hit a real object returned by the mock, or the block only computed values without invoking the mock.

solid answer

~60 s

MockK records by executing the lambda under a call recorder. If, when the block ends, no interceptable call on a mock was captured, it throws `Missing calls inside every { ... } block.` Triage in order: 1. **Is the receiver a mock?** A real instance, or the object under test built with a real collaborator, records nothing. 2. **Did the call reach the object at all?** Top-level and extension functions compile to static calls on a file facade and never touch the mock unless that facade is mocked; private members are not recorded by default. 3. **Is the receiver the mock's *return value*?** `every { repo.session().commit() }` records nothing unless `repo.session()` yields a mock — chained calls need a mock in between. 4. **Did the block actually make the call?** A block that only builds arguments, or short-circuits, records nothing. 5. **Did the call happen on the recording thread?** Work handed to another thread inside the block is outside the recording window. Contrast the neighbouring errors: `Failed matching mocking signature` means the call *was* recorded but matchers could not be bound, and `no answer found for: ...` means a real call on a strict mock found no stub.

code

kotlin · 14 lines
kotlin
val repo = mockk<Repo>()
val real = RealRepo()

// 1. not a mock -> Missing calls inside every { ... } block.
// every { real.find(1) } returns row

// 2. chained call through a real return value
// every { repo.session().commit() } just Runs
val session = mockk<Session>()
every { repo.session() } returns session
every { session.commit() } just Runs

// 3. block that never invokes the mock
// every { val key = buildKey(1) } returns row

go deeper

for a junior

Recognise the message means the block did not record a call on a mock, and check first that you are stubbing a mock rather than a real object.

for a middle

Work the list: not-a-mock, static/extension dispatch, chained call through a real value, block that never invokes anything.

for a senior

Triage across the three MockK exceptions, explain the recording boundary that separates them, and propose structural fixes — one call per block, arguments built outside, an injected interface instead of static mocking.

for a principal

Treat repeated occurrences as a design signal: collaborators reachable only through statics or internally constructed dependencies are what make tests need exotic recording, so change the seam rather than the test.

## What the exception literally means MockK does not parse your `every`/`coEvery`/`verify` lambda; it runs it with a call recorder installed and watches which calls it can intercept. `Missing calls inside every { ... } block.` is MockK saying: the block finished and I captured nothing I could turn into a stub. It is an *empty recording*, not a matching failure. ## The diagnosis checklist **1. The receiver is not a mock.** The most common cause and the most embarrassing: the field was reassigned to a real instance, the test builds the collaborator with a constructor, or the class under test creates its own dependency internally so the mock you configured is never the object being called. Print or assert the identity of what you are stubbing if you are unsure. **2. The call never dispatches to the instance.** Kotlin compiles top-level functions and extension functions to static methods on a file facade class, so the call is resolved at compile time and the mock instance is never consulted. The same is true of Java statics. Those need the corresponding static-mocking setup before any recording can happen; without it, the block executes the *real* function and records nothing. Private and internal members can also be invisible to recording unless the mock was created to record them. **3. You stubbed through a real return value.** `every { repo.session().commit() }` only records `commit()` if `repo.session()` already returns a mock. On a strict mock the inner call blows up first; on a relaxed mock it returns a chained child mock and does record; on a real object it records nothing. Stub the chain step by step, or make the intermediate a mock deliberately. **4. The block did not perform the call.** Blocks that only construct arguments, contain a conditional that skipped the call, or accidentally reference a method without invoking it (a method reference, a property that returns a lambda) record nothing. **5. The call happened off the recording thread.** The recorder is scoped to the block and to the thread running it. Anything you dispatch to an executor, a background thread, or code that resumes later runs outside the window. **6. The block was structured as an answer, not a call.** Matchers and calls belong to the recording half; the answer half (`returns`, `answers { }`) is a different scope, and calls you make there happen at answer time, not recording time. ## Read the neighbouring errors as a triage table Three MockK exceptions look similar to a candidate and mean very different things: - **`Missing calls inside every { ... } block.`** — nothing was recorded. Your target is not a mock, or the call did not dispatch to it. - **`Failed matching mocking signature for ...` with `left matchers: [...]`** — a call *was* recorded, but MockK could not bind the listed matchers to argument positions. Look at mixed matcher/literal arguments, a matcher value reused across parameters, or a tiny-value-space parameter. - **`no answer found for: Mock(#1).method(...)`** — recording succeeded; at *call* time a strict mock received an invocation no stub matched. Compare the arguments in the message with the matchers in your stub. Being able to say which of the three you are looking at, and what each implies, is most of the senior signal in this question. ## Practical habits that prevent it Keep exactly one mock call per recording block — one call, one stub — so an empty block is impossible to write by accident. Build arguments and slots *before* the block, not inside it. Do not put branching or loops inside a recording lambda; besides making empty recordings possible, the lambda may be executed more than once while MockK resolves the signature. And when a collaborator is a top-level or extension function, prefer a small injected interface over static mocking: the failure mode above disappears entirely because there is a real object to record on.

  • How do you tell 'Missing calls inside every' apart from 'no answer found for'?
    They sit on opposite sides of the recording boundary. 'Missing calls' happens while you are describing a stub: the block executed and MockK intercepted nothing, so the target is not a mock or the call did not dispatch to it. 'no answer found for' happens later, during the exercise phase: a strict mock really was called, but no recorded stub matched those arguments. The second message prints the actual call, so you can compare it against the matchers you wrote.
  • Why can stubbing a chained call fail even though the same expression works on a relaxed mock?
    A chain needs a mock at every step. A relaxed mock returns an automatically created child mock for an unstubbed method, so the inner call yields something recordable and the chain appears to work. A strict mock has no answer for the inner call, and a real intermediate object is not interceptable at all, so nothing is recorded. Stubbing each step explicitly makes the dependency visible rather than relying on child-mock creation.

saying these in an interview costs you the question

  • Reading the message as "the method was never called by the code under test" — it is about the recording block, not the exercise phase
  • Assuming a top-level or extension function can be stubbed on an instance mock without static mocking
  • Expecting a chained call to record when the intermediate value is a real object
  • Blaming flakiness instead of checking whether the stubbed receiver is the same instance the code uses
  • Putting conditionals, loops or side-effecting setup inside a recording lambda that MockK may run more than once

context