skip to content

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%

answer

  1. All = every element; Any = at least one
  2. it = element, position = index, nArgs = count
  3. spread with * like anyVararg()
  4. varargAll is vacuously true on an empty vararg
  5. predicate failures give poor messages — prefer literals when known

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

solid answer

~50 s

Both are spread into the vararg position and take a predicate over the elements. - `varargAll { ... }` matches only if **every** element it covers satisfies the predicate. - `varargAny { ... }` matches if **at least one** element does. Inside the block, `it` is the element under examination, and the scope adds two properties: `position`, the element's index within the vararg, and `nArgs`, the total number of vararg arguments in the call. Together they let you express positional and count constraints without spelling out every element — for example `varargAny { position < 3 || it == 5 }`. One caution: "all elements satisfy P" is trivially true when there are no elements, so `varargAll` alone is not a way to require that something was passed. If the call must carry arguments, state that explicitly with an `nArgs` condition or by writing literal leading elements.

code

kotlin · 11 lines
kotlin
interface Audit { fun record(vararg tags: String) }
val audit = mockk<Audit>(relaxUnitFun = true)

// every tag namespaced
verify { audit.record(*varargAll { it.startsWith("evt:") }) }

// the first tag is the start marker
verify { audit.record(*varargAny { position == 0 && it == "evt:start" }) }

// no more than three tags in the call
verify { audit.record(*varargAll { nArgs <= 3 }) }

go deeper

for a junior

Know the quantifiers: all elements versus at least one element, both spread into the vararg position.

for a middle

Add the scope properties — element, position, nArgs — and show a combined positional constraint; mention the empty-vararg caveat.

for a senior

Choose deliberately between literal elements, anyVararg and predicates based on what the test actually claims, and keep predicates small because their failure messages are weak.

for a principal

Set the expectation that predicate matchers are for genuinely variable argument lists; where the arguments are known, literal expectations produce better diagnostics and fewer accidental passes.

## Where these matchers live `varargAll` and `varargAny` are MockK matchers for a vararg parameter. Like `anyVararg()`, they are spread into the argument position with `*`, and they stand for a run of vararg elements rather than a single one: ```kotlin every { audit.record(*varargAll { it.startsWith("evt:") }) } just Runs every { audit.record(*varargAny { it == "evt:failure" }) } just Runs ``` They work identically in `every` and in `verify`, since both blocks use the same matcher DSL. ## The two quantifiers `varargAll { p }` is universal: the call matches only when **every** element it covers satisfies `p`. It expresses homogeneity — "all the tags were namespaced", "every id was positive", "nothing was blank". `varargAny { p }` is existential: the call matches when **at least one** element satisfies `p`. It expresses presence — "the failure event was among the tags", "someone passed a null-ish marker". Choosing the wrong quantifier produces the two classic false results. A `varargAll` used where you meant presence rejects any call that also contains unrelated elements. A `varargAny` used where you meant homogeneity happily accepts a call that is mostly wrong as long as one element is right — and, being an existential over interaction data, it tends to pass for reasons you did not intend. ## What the predicate block gives you Inside the lambda, `it` is the element being examined, typed as the vararg's element type. The matcher scope adds two more pieces of information: - **`position`** — the index of the element within the vararg. It turns "some element is X" into "the element at index 0 is X", which is usually what an assertion actually means. - **`nArgs`** — the number of vararg arguments the call carried. This is how you constrain the *shape* of the call rather than its contents: "at most three tags", "exactly two ids". Because both are available in the same predicate, positional and count logic compose freely: ```kotlin every { calc.sum(*varargAny { position == 0 && it == 5 }) } returns 1 every { calc.sum(*varargAll { nArgs <= 3 }) } returns 2 ``` ## The empty-vararg trap A universal quantifier over an empty collection is vacuously satisfied — "every element is X" has nothing to contradict it when there are no elements. So do not lean on `varargAll` to prove that something was passed at all. If the test's real claim is "at least one tag, and all of them namespaced", make the count explicit with an `nArgs` condition, or write literal leading elements so the recorded stub demands them. ## When to use these versus alternatives - **Exact expectation known** — write the literal elements. `verify { audit.record("evt:start", "user:42") }` is the clearest thing you can write, and its failure message is the most useful. - **Only presence matters** — `*anyVararg()`; you do not need a predicate to say "the call happened". - **A property over the elements matters** — that is exactly what `varargAll` / `varargAny` are for, and `position` / `nArgs` keep them from being vaguer than intended. ## Readability caution A predicate is opaque in a failure message: when a vararg matcher does not match, you learn that the call did not match, not which element broke the predicate. Keep the predicates small and single-purpose, prefer positional constraints over clever universal ones, and drop back to literal elements the moment you actually know what the call should contain. The value of these matchers is in the genuinely variable cases — a list of ids whose order or length is not fixed — not in dressing up an expectation you could have written out.

  • How do you express "the first vararg element is a start event, and there were at most three elements"?
    Use the scope properties in the predicate: `varargAny { position == 0 && it == "evt:start" }` pins the first element, and an `nArgs` condition constrains the count. Combining them in one predicate keeps the constraint in a single matcher, and both properties are available in the same block alongside the element value.
  • Why is varargAll a poor way to assert that arguments were actually passed?
    A universal condition over zero elements has nothing to contradict it, so a call with an empty vararg satisfies it. If the test's real claim includes "something was passed", say so explicitly with an `nArgs` condition or by writing the literal leading elements you expect.

saying these in an interview costs you the question

  • Using varargAll when the intent is "one of the elements was X"
  • Assuming varargAll guarantees at least one element was passed
  • Thinking the predicate only receives the element and not positional/count information
  • Writing an elaborate predicate for a call whose exact arguments are known, then struggling to read the failure
  • Believing these matchers work only in every blocks and not in verify

context