skip to content

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%

answer

  1. exactly = n is a named param outside the lambda
  2. bare verify = atLeast = 1 (not exactly once)
  3. exactly = 0 means never called
  4. no verifyNever API exists
  5. count is over matching invocations

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.

solid answer

~40 s

MockK's verify takes named parameters that control the count. verify(exactly = n) { mock.foo() } asserts the matching call happened exactly n times; verify(exactly = 0) { mock.foo() } asserts it never happened (a negative assertion). A bare verify { mock.foo() } defaults to atLeast = 1, i.e. one or more calls. The lambda body uses the same argument matchers (any(), eq(), capturing slots) as every. Counts apply per matching invocation, so verify(exactly = 2) { mock.foo(any()) } passes only when foo was invoked twice with any argument. Use exactly = 0 instead of a separate "never called" API — MockK has no verifyNever; the count expresses it.

code

kotlin · 6 lines
kotlin
val repo = mockk<Repo>(relaxed = true)
service.process(order)

verify(exactly = 1) { repo.save(order) }   // precisely once
verify(exactly = 0) { repo.delete(any()) } // never
verify { repo.audit(any()) }               // at least once (default)

go deeper

for a junior

Knows verify(exactly = n) and that exactly = 0 means never called.

for a middle

Knows the bare-verify default is atLeast = 1 and that counts are over matching invocations only.

for a senior

Explains why there is no verifyNever and how matchers in the lambda affect what gets counted.

for a principal

Frames exactly vs atLeast/atMost as a deliberate API design and advises teams when exact counts make tests brittle vs precise.

## What `verify` does `verify` is MockK's assertion that recorded calls on a **mock** (a fake object whose behavior you stubbed with `every`) actually occurred. It does **not** stub anything; it checks history after the code under test ran. ## The `exactly` parameter The count is passed as a **named argument** to `verify`, not inside the lambda: ```kotlin val repo = mockk<Repo>(relaxed = true) service.save(item) verify(exactly = 1) { repo.insert(item) } // exactly one call verify(exactly = 0) { repo.delete(any()) } // never called (negative) verify(exactly = 3) { repo.touch() } // precisely three ``` - `exactly = 0` is the idiomatic **"never happened"** assertion. MockK has **no** `verifyNever`; you express it with the count. - The lambda holds the **call expectation** with argument matchers: `any()`, `eq(x)` (the default for literals), `range(...)`, or a capturing `slot()`. ## Default when no count is given A bare `verify { repo.insert(item) }` is equivalent to `verify(atLeast = 1)` — it passes if the call occurred **one or more** times and fails only when it never occurred. So an unparameterised `verify` is **not** an exact-once check; if you need exactly-once, write `exactly = 1`. ## Counting semantics The count is over **invocations matching the lambda**. `verify(exactly = 2) { repo.find(any()) }` requires two calls to `find` with any argument. If `find` was called twice but with arguments that don't match your matcher, those calls don't count. ## Relation to other modes `exactly` is one of several count modes; the others are `atLeast`, `atMost`, and a `timeout`. They are mutually meaningful named params on the same `verify` overload.

  • How do you assert a call never happened?
    verify(exactly = 0) { mock.method(...) }. There is no verifyNever; the zero count is the negative assertion.
  • Does verify(exactly = 1) check the order relative to other calls?
    No. exactly only counts matching invocations of that one expectation. Ordering across calls needs verifyOrder or verifySequence.

Like checking a doorbell log: exactly = 3 says the bell rang precisely three times, exactly = 0 says it never rang.

saying these in an interview costs you the question

  • Thinking a bare verify { } means 'called exactly once'
  • Inventing a verifyNever() function
  • Putting the count inside the lambda instead of as a named param
  • Confusing exactly = 0 with confirmVerified

context