Kotest's SpecExecutionOrder controls the order whole spec classes run in, with values including Undefined, Lexicographic, Random, Annotated and FailureFirst. Walk through what each means, how the @Order annotation participates, and what FailureFirst needs in order to work.
answer
- SpecExecutionOrder = across specs; TestCaseOrder = within one spec
- Undefined default = discovery order
- Annotated honours @Order(n); unannotated run last
- FailureFirst needs persisted last-run failures on disk
- ordering detects leaks, isolation fixes them
basics
~20 sSpecExecutionOrder orders spec classes, not tests inside them. Undefined is the default and means discovery order; Lexicographic sorts by class name; Random shuffles; Annotated honours the @Order annotation, running annotated specs first in ascending order with unannotated ones after; FailureFirst runs previously failed specs first, which requires Kotest's persisted record of the last run's failures on disk.
solid answer
~60 s`SpecExecutionOrder` is set in your `AbstractProjectConfig` and decides the order **spec classes** execute in — a different axis from `TestCaseOrder`, which orders tests inside one spec. - `Undefined` — the default: whatever order discovery produced. No sorting cost, no guarantee. - `Lexicographic` — sorted by class name; deterministic and readable in reports. - `Random` — shuffled, the cross-spec analogue of random test order, useful for finding specs that leak global state into each other. - `Annotated` — respects Kotest's `@Order(n)` annotation on spec classes: lower values first, and specs with no annotation run afterwards. It is a sort key, not a dependency mechanism. - `FailureFirst` — runs specs that failed on the previous run before the rest, so a local red build fails fast. It only works if Kotest can persist the previous run's failures to disk between runs, so that state directory must be writable, and it belongs in .gitignore. In CI the practical picks are Lexicographic for determinism or Random for leak detection; FailureFirst is a local developer-loop optimisation.
code
kotlin · 12 linesobject ProjectConfig : AbstractProjectConfig() {
override val specExecutionOrder = SpecExecutionOrder.Annotated
}
@Order(0)
class SmokeSpec : FunSpec({ test("app boots") { } })
@Order(1)
class CheckoutSpec : FunSpec({ test("checkout succeeds") { } })
// no @Order — runs after the annotated ones
class ReportingSpec : FunSpec({ test("totals") { } })go deeper
Know that this setting orders whole spec classes and that the default gives no guarantee.
Name the values, explain @Order under Annotated including unannotated specs running last, and that FailureFirst relies on state persisted from the previous run.
Argue when to run randomised spec order in CI versus nightly, and insist ordering is a detector while isolation is the fix.
Set suite-wide policy: deterministic PR runs, randomised nightly runs, and a standard that no spec may depend on another's execution.
## Two ordering axes Kotest separates ordering into two settings, and mixing them up is the standard interview stumble. `TestCaseOrder` orders sibling test cases **inside** a spec. `SpecExecutionOrder` orders the **spec classes** relative to one another. They are configured in different places and answer different questions. ## The values **Undefined** is the default. The engine runs specs in whatever order discovery produced. There is no sorting cost and no promise about the order; do not build anything on it. **Lexicographic** sorts spec classes by name. The benefit is determinism: two runs of the same suite report in the same order, so diffing reports and comparing timings across builds actually works. **Random** shuffles spec classes. Its purpose mirrors random test order but one level up: it exposes specs that leak *global* state into one another — a mutated singleton, a system property, a shared test database left dirty, a static mock never reset. Under a fixed order such coupling can hide indefinitely. **Annotated** uses Kotest's `@Order` annotation on spec classes: annotated specs run first in ascending order of their value, and unannotated specs run after them. It is a sorting hint only — it does not express or enforce dependencies. If two specs genuinely must run in a given order, that is a design problem in the tests, not a scheduling problem; `@Order` is legitimate for coarse pragmatics such as putting a fast smoke spec first so the run fails early. **FailureFirst** reorders so specs that failed on the previous run go first. That obviously requires knowing what failed last time, which means Kotest writes that information to disk between runs. Practical consequences: the state directory must exist and be writable by the test process, it should be gitignored, and the very first run — or a CI agent with a fresh workspace — has nothing recorded, so the ordering degrades to the normal case. That is exactly why FailureFirst is a local developer-loop feature: on ephemeral CI agents there is usually no prior state to use. ## Choosing For CI, pick determinism (`Lexicographic`) if you compare reports and timings across builds, or `Random` if you are actively hunting cross-spec state leaks. Running `Random` continuously in CI is defensible for a healthy suite and painful for a legacy one; a common compromise is a nightly randomised run alongside a deterministic PR run, so leaks are found without making every PR intermittently red. For local work, `FailureFirst` shortens the edit-run loop meaningfully on a big suite: you see the specs you just broke without waiting for everything else. ## What it does not solve Ordering is not isolation. If specs interfere, changing their order changes which one fails, not whether interference exists. The durable fixes live elsewhere: per-test transactional rollback, avoiding global mutable state, resetting shared fakes in lifecycle hooks, and Kotest's isolation settings for state held on the spec instance itself. Reach for ordering as a *detector* and as an ergonomics knob — never as the mechanism that makes a suite correct.
- Is @Order a safe way to express that one spec must run before another?No. It is a sort key under the Annotated mode, not a dependency declaration — nothing verifies the relationship, it silently does nothing under any other ordering mode, and it gives no guarantee once specs can run concurrently. A spec that requires another spec to have run first is coupled through shared state, and the fix is to give it its own setup rather than to schedule around the problem.
saying these in an interview costs you the question
- Confusing SpecExecutionOrder with TestCaseOrder
- Treating @Order as a dependency mechanism that guarantees one spec runs before another
- Expecting FailureFirst to work on a fresh CI workspace with no recorded previous run
- Claiming the default sorts spec classes alphabetically