skip to content

Kotest's test config accepts an invocations parameter. What does it do, which kinds of test can use it, and when is repeating a test body the wrong tool for the job?

level: middleimportance: nice to knowfreq 22%

answer

  1. invocations = loop around a leaf test body
  2. containers cannot take invocations
  3. one test case, one result — any repetition failing fails it
  4. input variety = property testing, not invocations
  5. repetition is not retry

basics

~20 s

invocations runs a leaf test's body the given number of times; a failure in any repetition fails that one test case. It cannot be used on containers. It is the wrong tool for exploring input space — that is property testing — and a poor substitute for fixing a flaky test.

solid answer

~60 s

`test("x").config(invocations = 100) { ... }` repeats the test body 100 times. It is a repetition count on a **leaf test**; containers cannot take it, because a container's body registers children rather than asserting. The reporting model is one test case with repeated execution: a failure in any repetition fails that test. Do not assume per-repetition lifecycle callbacks — model it as a loop around the body, so anything you need reset per repetition must be reset inside the body. Legitimate uses are narrow: shaking out a suspected race by hammering one code path, or a cheap warm-up. It is the wrong tool for two common cases. If you are repeating with different inputs, you want Kotest's property testing, which generates inputs and shrinks failures instead of running the same case 100 times. And repeating a flaky test until it passes is not a fix — `invocations` makes flakiness *more* visible, not less, since one bad repetition fails the test. On versions: the old per-test `threads` parameter that paired with `invocations` in Kotest 4 is not the Kotest 5 way to get parallelism — the concurrency settings are.

code

kotlin · 9 lines
kotlin
class CounterSpec : FunSpec({

   test("increments are not lost under contention")
      .config(invocations = 500) {
         val counter = Counter()
         counter.incrementFromManyCallers()
         counter.value shouldBe expected
      }
})

go deeper

for a junior

Know invocations repeats a leaf test's body and that any failing repetition fails the test.

for a middle

Add the container restriction, the single-test-case reporting model, and the fact that state persists across repetitions unless the body resets it.

for a senior

Position it as a diagnostic for nondeterminism, contrast it with property testing for input coverage, and reject it as a flake remedy.

for a principal

Set the standard that permanent high invocation counts are a smell and that suite time spent on repetition must be justified by a real race being hunted.

## What invocations does `invocations` is a field on Kotest's test config: `test("name").config(invocations = 10) { ... }` executes the body ten times. Conceptually it wraps the test body in a loop. Two constraints matter. First, it applies to **leaf tests only** — a container's body exists to register children, and repeating registration is meaningless, so containers cannot take it. Second, the unit of reporting is still one test case: ten invocations do not appear as ten results, and a failure in any one of them fails that single test. That second point drives the practical advice: treat it as a loop, not as ten independent tests. Anything the body mutates persists into the next repetition unless the body resets it. If repetition two only passes because repetition one left a row in the database, the test is lying — and it will keep lying until someone runs it once. ## Where it is genuinely useful **Shaking out a race.** You suspect a concurrency bug in production code. Running the exercising test a few hundred times raises the chance of hitting the bad interleaving. This is a diagnostic use — often turned up temporarily while you hunt, then dialled back or removed, because a permanent high invocation count is a permanent slowdown. **Warming up.** Occasionally a first-call cost (class loading, JIT, a lazy connection) distorts a timing-sensitive assertion, and a couple of invocations smooths it. This is rare and slightly suspect; assertions that depend on warm-up are usually the real problem. ## Where it is the wrong tool **Exploring input space.** If your intent is "try this with lots of different values", `invocations` gives you the *same* value many times — there is no generation and nothing to shrink. Kotest's property testing is the tool for that: it generates inputs, injects edge cases, and on failure shrinks to a minimal counterexample and prints a seed to replay. Running one fixed case 500 times finds nothing that running it once did not. **Papering over flakiness.** People sometimes reach for repetition hoping to stabilise a flaky test. It does the opposite: since any failing repetition fails the test, a 1-in-50 flake becomes near-certain at 100 invocations. That is arguably the *correct* behaviour — it converts intermittent into deterministic — but it is not a way to make a flaky test green. Retry semantics and repetition are different things, and confusing them is a common interview tell. **Getting parallelism.** Repetitions are repetitions. In Kotest 4 there was a per-test `threads` parameter that paired with `invocations`; in Kotest 5 the way to run work concurrently is the project-level concurrency configuration, not a per-test thread count. Say that plainly if asked, and point at the concurrency settings. ## Interview framing A strong answer states the mechanic in one line, names the leaf-only constraint and the single-test-case reporting model, then spends most of its time on the judgment: repetition is a diagnostic for nondeterminism in the code under test, property testing is the tool for input coverage, and neither is a remedy for a flaky test. Candidates who only know the parameter exists give the first line; candidates who have run a real suite give the rest.

  • A colleague sets invocations = 200 on a test to make it less flaky. What do you tell them?
    Repetition is not retry. Because a failure in any repetition fails the single test case, a rare flake becomes almost certain to appear rather than disappearing. That is useful as a diagnosis — it turns an intermittent failure into a reproducible one — but the fix is to find the nondeterminism: shared state, real time, real IO, or ordering assumptions.

saying these in an interview costs you the question

  • Thinking invocations reports each repetition as a separate test result
  • Trying to apply invocations to a container
  • Using invocations to vary inputs instead of Kotest's property testing
  • Believing repeating a test makes a flaky test pass more often

context