How do you set Kotest's isolation mode for one spec versus for a whole project, and which setting wins when both are present?
answer
- spec: override fun isolationMode()
- project: AbstractProjectConfig.isolationMode
- spec → project → SingleInstance default
- override, not merge — spec can opt out of a stricter default
- project default change = suite-wide cost
basics
~20 sPer spec: override the spec's isolationMode() function to return an IsolationMode. Project-wide: set the isolationMode property on your AbstractProjectConfig subclass. The spec-level setting takes precedence; specs that declare nothing fall back to the project default, and failing that, SingleInstance.
solid answer
~50 sTwo levels, with the narrower one winning. **Per spec** — override the function on the spec class: ```kotlin class CartTest : FunSpec({ /* … */ }) { override fun isolationMode() = IsolationMode.InstancePerLeaf } ``` **Project-wide** — set the property in your `AbstractProjectConfig` subclass: ```kotlin class ProjectConfig : AbstractProjectConfig() { override val isolationMode = IsolationMode.InstancePerRoot } ``` Resolution order is spec → project → the built-in default of `SingleInstance`. A spec that declares nothing inherits the project value; a spec that declares one ignores the project value entirely — there is no merging or "most isolating wins". Practically: keep the project default cheap and let the handful of specs that genuinely need per-test freshness opt in. Flipping the project default is a suite-wide performance and behaviour change, because every spec body and container block starts re-executing more often.
code
kotlin · 9 linesclass CartTest : FunSpec({
test("starts empty") { }
}) {
override fun isolationMode() = IsolationMode.InstancePerLeaf // wins for this spec
}
class ProjectConfig : AbstractProjectConfig() {
override val isolationMode = IsolationMode.InstancePerRoot // default for specs that declare nothing
}go deeper
Name the two places the mode can be set and state that the spec-level setting wins.
Show both code shapes, give the resolution order including the SingleInstance fallback, and note there is no merging.
Add the operational judgement: project defaults are cheap-by-default, opt in per spec, and measure before a suite-wide flip.
Treat it as policy versus enforcement — a project default is advisory, so the real control is convention, base specs and review.
## The two places the mode can be declared Kotest resolves a spec's isolation mode from the narrowest declaration outwards. ### Spec level The spec class exposes an overridable function returning the mode: ```kotlin class CartTest : FunSpec({ test("…") { } }) { override fun isolationMode() = IsolationMode.InstancePerLeaf } ``` Because the spec body is a constructor lambda, the override lives in a class body attached after it — which is why specs that configure anything are written with the `{ … }) { … }` shape. The same pattern is used for other per-spec settings. A shared base spec can carry the override so a whole family of specs gets the same isolation without repeating it: ```kotlin abstract class IsolatedSpec(body: FunSpec.() -> Unit) : FunSpec(body) { override fun isolationMode() = IsolationMode.InstancePerLeaf } ``` ### Project level The project configuration class — a subclass of `AbstractProjectConfig` — carries a project-wide default: ```kotlin class ProjectConfig : AbstractProjectConfig() { override val isolationMode = IsolationMode.InstancePerRoot } ``` That value applies to every spec that does not state its own. (How Kotest discovers the project config class is a separate configuration topic; here what matters is the precedence relationship.) ## Precedence Spec beats project; project beats the framework default. If no one declares anything, Kotest uses `SingleInstance`. The rule is a simple override, not a combination: a spec asking for `SingleInstance` gets exactly that even when the project default is a fresh-instance mode — there is no "most isolating wins" merge. That cuts both ways, and it is worth saying out loud in an interview: a spec can *opt out* of a stricter project default just as easily as it can opt in to a stricter one, so a project-wide isolation policy is a default, not an enforcement mechanism. ## How to use the two levels well **Keep the project default cheap.** Changing it is a suite-wide change: every spec body and every container block starts re-executing more often, heavy `beforeSpec` setup is multiplied, and side effects written inside container blocks are duplicated. On a large suite that can turn minutes into tens of minutes and can turn green into red for tests that assumed a container's setup ran once. If you do want a stricter project default, roll it out and measure, rather than flipping it in a Friday commit. **Opt in where it pays.** Legacy specs full of accumulated mutable state are the honest use case for a per-spec fresh-instance mode: you get correct isolation now, and you can refactor the state out later. New specs should generally not need it — build mutable fixtures inside the test or rebuild them in `beforeTest`, and the default mode is both faster and clearer. **Prefer the coarsest mode that solves the problem.** If tests only pollute across top-level branches, `InstancePerRoot` (Kotest 6.0+, the recommended fresh-instance mode in Kotest 6) costs far less than a per-leaf mode. **Make the choice visible.** A spec whose behaviour depends on its isolation mode should say so near the top; a reader who does not see the override will reason about shared state incorrectly. Some teams enforce it via a base spec so the mode is declared in exactly one place. ## Common mistakes - Declaring the mode inside the spec *body* lambda by assigning a local variable and expecting it to take effect — the override belongs to the class, and a stray local does nothing. - Assuming a stricter project default protects every spec; a spec-level declaration silently overrides it. - Setting a fresh-instance project default to fix one leaky spec, paying the cost across the whole suite. - Expecting the mode to affect anything outside the spec object — it does not reset companions, singletons or external systems. ## What interviewers listen for The two mechanisms named precisely, the direction of precedence, and the judgement that project-wide isolation changes are a performance and behaviour event rather than a config tweak.
- Your project default is a fresh-instance mode but one spec declares SingleInstance. What runs for that spec?SingleInstance — the spec-level declaration wins outright and there is no merging with the project value. This means a project-wide isolation policy is only a default, not an enforcement mechanism; if you need it enforced, that has to come from code review or a shared base spec rather than from the config.
- How would you apply one isolation mode to a family of integration specs without repeating the override in each one?Put the override on an abstract base spec that forwards the body lambda to the spec constructor, then have the integration specs extend it. The setting is then declared in exactly one place and is visible to anyone reading the base class, while unrelated specs keep the cheaper project default.
saying these in an interview costs you the question
- Thinking the more isolating of the spec and project settings wins
- Trying to set the mode by assigning a variable inside the spec body lambda
- Changing the project default to fix a single leaky spec
- Believing a project-wide setting cannot be overridden by an individual spec
- Assuming the setting has any effect on state outside the spec instance