Which Kotest matchers would you use to assert membership, size, and ordering on collections and substrings on strings? Give concrete examples.
answer
- shouldContain / shouldContainAll for membership
- shouldHaveSize, shouldBeEmpty
- Exactly = order matters; InAnyOrder = multiset
- string: shouldStartWith/EndWith/Contain/Match
- argument matchers infix; predicate matchers dotted
basics
~10 sFor lists use matchers like shouldContain (has an element), shouldHaveSize (length), shouldBeEmpty, and shouldContainExactly (same elements in order). For strings use shouldContain, shouldStartWith, shouldEndWith, and shouldMatch for a regex.
solid answer
~30 sKotest ships rich collection and string matchers. Collections: `list shouldContain 3`, `list shouldContainAll listOf(1,2)`, `list shouldHaveSize 4`, `list.shouldBeEmpty()`, `list shouldContainExactly listOf(1,2,3)` (order-sensitive), `list shouldContainExactlyInAnyOrder listOf(3,1,2)` (order-agnostic), `list.shouldBeSorted()`, `list shouldNotContain 9`. Strings (in `io.kotest.matchers.string`): `s shouldContain "ell"`, `s shouldStartWith "he"`, `s shouldEndWith "lo"`, `s shouldMatch Regex("h.*o")` or a pattern string, `s shouldHaveLength 5`, `s.shouldBeBlank()`, `s shouldContainIgnoringCase "HELLO"`. Most are infix; predicate-free ones like `shouldBeEmpty` are extension functions called with a dot. `shouldContainExactly` vs `shouldContainExactlyInAnyOrder` is the key distinction interviewers probe — the first cares about order and duplicates, the second only about multiset equality.
code
kotlin · 13 linesimport io.kotest.matchers.collections.*
import io.kotest.matchers.string.*
val names = listOf("ann", "bob", "cy")
names shouldHaveSize 3
names shouldContain "bob"
names shouldContainExactlyInAnyOrder listOf("cy", "ann", "bob")
names.shouldBeSorted()
val email = "[email protected]"
email shouldContain "@"
email shouldEndWith ".com"
email shouldMatch Regex("[^@]+@[^@]+\\.[a-z]+")go deeper
Knows shouldContain and shouldHaveSize for lists and shouldContain/shouldStartWith for strings.
Correctly chooses shouldContainExactly vs shouldContainExactlyInAnyOrder and uses regex/edge string matchers.
Articulates the infix-vs-dotted distinction, ordering matchers, and how matcher choice prevents flaky tests.
Drives a convention so unordered collections always use order-agnostic matchers, eliminating a whole class of flakiness across the suite.
## Collection matchers From `io.kotest.matchers.collections.*`: - **Membership:** `shouldContain(e)`, `shouldNotContain(e)`, `shouldContainAll(c)`, `shouldContainAnyOf(...)`. - **Size/emptiness:** `shouldHaveSize(n)`, `shouldBeEmpty()`, `shouldNotBeEmpty()`, `shouldHaveSingleElement(e)`. - **Exact contents:** `shouldContainExactly(e1, e2, ...)` — same elements, **same order**, same duplicates. `shouldContainExactlyInAnyOrder(...)` — same elements as a **multiset**, order ignored. - **Ordering:** `shouldBeSorted()`, `shouldBeMonotonicallyIncreasing()`, `shouldContainInOrder(...)` (subsequence in order). - **Uniqueness:** `shouldBeUnique()`, `shouldContainDuplicates()`. ```kotlin import io.kotest.matchers.collections.* val xs = listOf(1, 2, 3) xs shouldContain 2 xs shouldHaveSize 3 xs shouldContainExactly listOf(1, 2, 3) // order matters xs shouldContainExactlyInAnyOrder listOf(3, 2, 1) // order ignored xs.shouldBeSorted() emptyList<Int>().shouldBeEmpty() ``` ## String matchers From `io.kotest.matchers.string.*`: - **Substring:** `shouldContain(sub)`, `shouldNotContain(sub)`, `shouldContainIgnoringCase(sub)`. - **Edges:** `shouldStartWith(prefix)`, `shouldEndWith(suffix)`. - **Regex:** `shouldMatch(regex)` accepts a `Regex` or pattern `String` (whole-string match). - **Shape:** `shouldHaveLength(n)`, `shouldBeEmpty()`, `shouldBeBlank()`, `shouldHaveLineCount(n)`, `shouldContainOnlyDigits()`. ```kotlin import io.kotest.matchers.string.* val s = "hello world" s shouldContain "o w" s shouldStartWith "hello" s shouldEndWith "world" s shouldMatch Regex("hello.*") s shouldHaveLength 11 ``` ## Infix vs dotted Matchers that take an argument are **infix** (`xs shouldContain 2`). Argument-free predicate matchers are extension functions invoked with a dot and parentheses (`xs.shouldBeEmpty()`). Mixing them up is a common compile error. ## The exactly trap `shouldContainExactly` is the strict one: it fails if order differs or duplicates differ. Reach for `shouldContainExactlyInAnyOrder` when the source (e.g. a `Set` or query result) has no guaranteed order — otherwise you write flaky tests.
- When asserting on a Set's contents, which exact-match matcher is correct?shouldContainExactlyInAnyOrder, because a Set has no guaranteed iteration order; shouldContainExactly would be flaky.
- Why does `xs.shouldBeEmpty()` use a dot but `xs shouldContain 2` does not?shouldBeEmpty takes no argument so it's a plain extension function; shouldContain takes an argument and is declared infix.
saying these in an interview costs you the question
- Using shouldContainExactly on an unordered source, producing flaky tests
- Thinking shouldContain checks substring containment for lists (it checks element membership)
- Calling infix matchers with a dot, or predicate matchers without parentheses
- Believing shouldMatch does a partial match (it matches the whole string)