skip to content

Vararg Matching

Varargs need their own matcher family because one parameter hides many arguments. Interviewers use this niche to spot people with genuine hands-on MockK depth.

on this pageshow

explore

questions

3

You are stubbing a MockK mock of an interface method declared as fun log(vararg parts: String). Why does every { log.log(any()) } fail to match a call that passes three arguments, and what does MockK give you to match a call with any number of vararg elements?

level: middleimportance: must knowfreq 35%

answer

  1. each expression = one vararg element matcher
  2. any() ⇒ exactly one element
  3. *anyVararg() ⇒ any element count
  4. spread with * like a real array
  5. leading fixed params keep normal matchers

basics

~20 s

In the every block each value you write in a vararg position records one element matcher, so any() describes a call with exactly one element. Use MockK's anyVararg() spread into the call — every { log.log(*anyVararg()) } — to match any number of elements.

solid answer

~40 s

MockK's DSL records matchers per argument *as written*. A vararg parameter is filled from however many expressions you place in that position, so `log.log(any())` records a single element matcher and only matches invocations that passed exactly one element. Three real arguments mean three elements, so the recorded stub does not match and you get "no answer found" (or the relaxed/unit default, if the mock was created relaxed). The purpose-built matcher is `anyVararg()`, spread with `*` into the vararg position: `every { log.log(*anyVararg()) } just Runs`. It stands for the whole vararg tail regardless of how many elements arrived — zero, one or twenty — and works the same way in `verify { log.log(*anyVararg()) }`. If the method also has fixed leading parameters, they keep the ordinary matcher rules: `every { log.log(any(), *anyVararg()) }`.

code

kotlin · 8 lines
kotlin
interface Log { fun log(vararg parts: String) }
val log = mockk<Log>()

every { log.log(any()) } just Runs        // matches log("a") only
every { log.log(*anyVararg()) } just Runs // matches log(), log("a"), log("a","b","c")

log.log("a", "b", "c")
verify { log.log(*anyVararg()) }

go deeper

for a junior

Know the shape: use *anyVararg() when you do not care how many arguments were passed, and that any() means exactly one element.

for a middle

Explain the element-wise recording model that causes the mismatch, and how the symptom differs between strict and relaxed mocks.

for a senior

Use it deliberately — anyVararg() when the assertion is about whether the call happened, explicit elements or predicates when it is about what was passed — and diagnose non-firing vararg stubs by element count first.

for a principal

Frame vararg collaborators (loggers, metrics) as low-value verification targets and set a convention that keeps such stubs relaxed rather than accumulating brittle element-shaped expectations.

## What a vararg parameter is at the call site In Kotlin, `fun log(vararg parts: String)` accepts any number of `String` arguments; the compiler collects them into an array for the callee. Inside MockK's `every { }` / `verify { }` blocks you are not calling the method for real — you are *recording* what the arguments should look like. The recording is positional and element-wise: each expression you write in the vararg position contributes one element matcher. That is why `every { log.log(any()) }` is not "match any call to log". It is "match a call whose vararg carried exactly one element, and that element can be anything". A production call `log.log("a", "b", "c")` carries three elements, so it does not match the recorded stub. ## The symptom On a strict mock, the unmatched call fails at run time with MockK's "no answer found for" message naming the mock and the invocation. On a relaxed mock or one created with `relaxUnitFun = true`, the call quietly takes the default behaviour, so the mismatch shows up later as a `verify` that fails or a stub that never fires — which is the more confusing case. If a vararg stub "just doesn't take effect", element count is the first thing to check. ## anyVararg() `anyVararg()` is MockK's matcher for the whole vararg tail. It is spread into the call with `*`, exactly like passing an array to a vararg parameter in ordinary Kotlin: ```kotlin every { log.log(*anyVararg()) } just Runs verify { log.log(*anyVararg()) } ``` It matches zero elements, one element, or many, so it is the right default whenever the test does not care what was logged and only cares that logging happened — or, on the stubbing side, when the mock must simply accept every shape of call. ## Mixed signatures Fixed parameters that precede the vararg behave normally: `fun log(level: Level, vararg parts: String)` is stubbed as `every { log.log(any(), *anyVararg()) }`. The vararg matcher only ever stands for the vararg tail; it does not swallow the preceding parameters. ## When you want to say more than "anything" `anyVararg()` is the blunt instrument. MockK also gives you predicate matchers over the elements — `varargAll { }` requires every covered element to satisfy a condition, `varargAny { }` requires at least one — and you can write literal elements before a spread matcher to pin specific positions. Reach for those when the assertion is about *what* was passed; reach for `anyVararg()` when it is about *whether* the call happened. ## Practical guidance - Stubbing a logger, metrics recorder, or any "fire and forget" vararg collaborator: `*anyVararg()`, or create the mock relaxed and skip the stub entirely. - Verifying a specific call: write the literal elements you expect, which reads better than a predicate — MockK matches them element-wise. - Debugging a vararg stub that does not fire: count the elements in the recorded stub versus the real call before suspecting anything more exotic. It is almost always the count. - Remember the same rules apply in `verify`: a `verify { log.log(any()) }` that "proves" logging happened is really asserting a single-element call, which may pass for the wrong reason or fail for a trivial one.

  • The method is `fun log(level: Level, vararg parts: String)`. How do you stub it for any level and any parts?
    Write `every { log.log(any(), *anyVararg()) }`. The leading fixed parameter follows the ordinary matcher rules and needs its own `any()`; `anyVararg()` stands only for the vararg tail, so it never absorbs preceding parameters.
  • How does the mismatch present itself differently on a strict mock versus a relaxed one?
    A strict mock throws at call time with MockK's "no answer found" message naming the invocation, so the cause is fairly visible. A relaxed mock silently returns its default instead, so the stub simply never fires and the failure surfaces later as a wrong result or a failing verification — which is why vararg element counts are worth checking early when a relaxed mock behaves oddly.

saying these in an interview costs you the question

  • Believing any() in a vararg position matches any number of elements
  • Thinking a vararg parameter is matched as a single array argument by the DSL
  • Calling anyVararg() without the spread operator and expecting it to compile as a single element
  • Assuming anyVararg() also covers the fixed parameters that precede the vararg
  • Concluding the mock is broken when a relaxed mock silently ignores a stub that never matched

context

open as a page

MockK provides varargAll and varargAny for constraining the elements of a vararg parameter. What does each one assert about the arguments, and what does the predicate block expose besides the element value itself?

level: middleimportance: should knowfreq 25%

basics

~20 s

varargAll matches when every element it covers satisfies the predicate; varargAny matches when at least one does. Inside the block, it is the element, and the scope also exposes position (the element's index in the vararg) and nArgs (how many vararg arguments there were).

open as a page

Using MockK, can one stub pin the first vararg elements to exact values while constraining the remaining ones with a predicate — for example, first two elements exactly 5 and 6, everything after that equal to 7? How is that written and what does it match?

level: seniorimportance: should knowfreq 20%

basics

~20 s

Yes. Write the literal elements first and spread a vararg matcher after them: every { calc.manyMany(5, 6, *varargAll { it == 7 }) } returns 3. The literals pin those positions element-wise; the spread matcher covers the remaining elements.

open as a page