Kotest test names are free-text strings rather than method identifiers. How are those names supplied, and where do they end up mattering?
answer
- name = string argument, evaluated at registration
- identity = full path in nested styles
- shown in IDE, XML report, name filters
- style keyword prefixes: Given:/Feature:
- strings are not symbols - no rename refactor
basics
~20 sThe name is the string argument you pass to the DSL builder, evaluated when the spec registers its tests. It becomes the test's identity: shown in IDE and CI reports, used for name-based filtering, and it must be unique within its scope.
solid answer
~50 sIn Kotest you name a test by passing a string to the builder - test("returns zero for an empty basket") - rather than by naming a method. The string is a normal Kotlin expression evaluated at registration time, so it can be interpolated or computed. That name is the test's identity. It is what the IDE tree, the console output and the JUnit-Platform XML show, and it is what name-based filtering matches on. In nested styles the identity is the full path of enclosing container names plus the leaf name, and some styles prefix the keyword when rendering - BehaviorSpec shows Given:/When:/Then:, FeatureSpec shows Feature:/Scenario: - so you should not repeat the keyword in the string. The upside is readable sentences and no identifier gymnastics; the cost is that names are not symbols, so an IDE rename refactor does not touch them, and duplicate names inside one scope are a real hazard.
code
kotlin · 10 linesclass BasketSpec : FunSpec({
test("returns zero for an empty basket") {
Basket().total() shouldBe 0
}
listOf(1, 2, 3).forEach { n ->
test("totals $n items") { // unique because n is in the name
Basket(items = n).count() shouldBe n
}
}
})go deeper
Know the name is the string you pass, that it shows in reports, and that it should read as a sentence about behaviour.
Add that names are evaluated at registration, that nested identity is the container path, and that duplicates in a scope are a real problem.
Discuss identity stability for CI history and filters, the duplicate-name policy, and conventions for generated names.
Treat names as a public interface of the suite: they drive dashboards, filters and non-engineer readability, so naming convention is worth codifying and reviewing.
## How a name is supplied Every Kotest style builds tests by calling a function whose first argument is the name: test("..."), should("..."), describe("..."), given("..."), scenario("..."), or in StringSpec the string itself with a lambda attached. Because it is an ordinary argument, the name is computed at registration time. You can interpolate values into it, build it from a constant, or generate it in a loop. AnnotationSpec is the exception: there the test is a method, so the method identifier is the name and free text is not available. That is one of the concrete costs of choosing that style. ## Where the name shows up - The IDE test tree and the console or HTML output of the build. - The JUnit-Platform XML that CI servers parse, which is how dashboards track a test's history over time. - Name-based filtering, including Kotest's own kotest.filter.tests system property. In nested styles the identity is a path: the container names from the root down to the leaf. Renaming a container therefore renames every descendant's identity, which resets history in dashboards and breaks any saved filter expression. In flat styles the identity is a single segment, which is more stable but carries no grouping information. ## Style-added prefixes Some styles decorate the rendered name with their keyword. BehaviorSpec renders Given:, When:, Then:; FeatureSpec renders Feature:, Scenario:. Write the string without the keyword - given("a stack with one element"), not given("Given a stack with one element") - or reports read 'Given: Given a stack'. ## The tradeoffs of sentence naming Upside: the name is prose, so a failure message reads like a sentence about the behaviour, and non-engineers can read the report. There is no camelCase or underscore encoding, and no length limit to fight. Downside one: names are strings, not symbols. No compiler check, no rename refactor, no find-usages. A typo lives forever and a copy-paste duplicate is easy. Downside two: uniqueness. Two tests with the same name in the same scope are ambiguous for anything that identifies a test by name. Kotest 5 exposes a duplicate-name policy, DuplicateTestNameMode, with Silent, Warn and Error, so a suite can choose to fail rather than tolerate collisions; the default warns. Collisions most often appear when names are generated from data with a repeated field. Downside three: filter hostility. Names full of punctuation, quotes or regex metacharacters are awkward to pass to a filter expression on a command line. Sentence names are best kept plain: lower-case prose, no quotes, no leading or trailing whitespace. ## Practical conventions Write the name as a claim about behaviour, in the third person: 'returns zero for an empty basket', not 'test basket' or 'should work'. Keep the subject in the container name and the assertion in the leaf name in nested styles, so the concatenated path reads as one sentence. When names are generated, always include a field that makes them unique.
- What happens if two tests in the same scope end up with the same name?Kotest 5 treats it as a policy question via DuplicateTestNameMode: Silent, Warn (the default) or Error. Under the non-failing modes the run continues and Kotest disambiguates the second name so both tests still execute; under Error the spec fails. Collisions matter because anything identifying a test by name - filters, CI history - becomes ambiguous, so generated names should always include a distinguishing field.
- Which Kotest style does not give you free-text names?AnnotationSpec, because its tests are annotated methods and the method identifier is the name. That is deliberate: the style exists to mirror an annotation-driven test class during migration, and giving up sentence naming is one of the reasons it is not recommended as a permanent style.
saying these in an interview costs you the question
- Thinking test names are compile-time symbols that a rename refactor updates
- Repeating the style keyword in the string ('Given a stack' under given)
- Generating names from data without a unique field and assuming duplicates are harmless
- Believing renaming a container has no effect on nested test identities