kotlin-testing/SKILL.md
Kotlin testing patterns with Kotest, MockK, coroutine testing, property-based testing, and Kover coverage. Follows TDD methodology with idiomatic Kotlin practices.
npx skillsauth add lidge-jun/cli-jaw-skills kotlin-testingInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Comprehensive Kotlin testing patterns for writing reliable, maintainable tests following TDD methodology with Kotest and MockK.
./gradlew koverHtmlReport and verify 80%+ coverageRED → Write a failing test first
GREEN → Write minimal code to pass the test
REFACTOR → Improve code while keeping tests green
REPEAT → Continue with next requirement
For full step-by-step EmailValidator walkthrough, see references/code-examples.md.
class UserServiceTest : FunSpec({
val repository = mockk<UserRepository>()
val service = UserService(repository)
test("getUser returns user when found") {
val expected = User(id = "1", name = "Alice")
coEvery { repository.findById("1") } returns expected
val result = service.getUser("1")
result shouldBe expected
}
test("getUser throws when not found") {
coEvery { repository.findById("999") } returns null
shouldThrow<UserNotFoundException> {
service.getUser("999")
}
}
})
For StringSpec, BehaviorSpec, and DescribeSpec examples, see references/code-examples.md.
// Equality
result shouldBe expected
result shouldNotBe unexpected
// Strings
name shouldStartWith "Al"
name shouldEndWith "ice"
name shouldContain "lic"
name shouldMatch Regex("[A-Z][a-z]+")
name.shouldBeBlank()
// Collections
list shouldContain "item"
list shouldHaveSize 3
list.shouldBeSorted()
list.shouldContainAll("a", "b", "c")
list.shouldBeEmpty()
// Nulls
result.shouldNotBeNull()
result.shouldBeNull()
// Types
result.shouldBeInstanceOf<User>()
// Numbers
count shouldBeGreaterThan 0
price shouldBeInRange 1.0..100.0
// Exceptions
shouldThrow<IllegalArgumentException> {
validateAge(-1)
}.message shouldBe "Age must be positive"
shouldNotThrow<Exception> {
validateAge(25)
}
For custom matchers, see references/code-examples.md.
class UserServiceTest : FunSpec({
val repository = mockk<UserRepository>()
val logger = mockk<Logger>(relaxed = true) // Returns defaults for all calls
val service = UserService(repository, logger)
beforeTest {
clearMocks(repository, logger)
}
test("findUser delegates to repository") {
val expected = User(id = "1", name = "Alice")
every { repository.findById("1") } returns expected
val result = service.findUser("1")
result shouldBe expected
verify(exactly = 1) { repository.findById("1") }
}
test("suspend function mocking") {
coEvery { repository.findById("1") } returns User(id = "1", name = "Alice")
val result = service.getUser("1")
result.name shouldBe "Alice"
coVerify { repository.findById("1") }
}
})
For advanced MockK patterns (argument capture, spy, coroutine mocking), see references/code-examples.md.
Use runTest from kotlinx.coroutines.test for suspend functions and coroutines:
test("concurrent fetches complete together") {
runTest {
val service = DataService(testScope = this)
val result = service.fetchAllData()
result.users.shouldNotBeEmpty()
}
}
For Flow testing, TestDispatcher, and advanced coroutine patterns, see references/code-examples.md.
Property-based testing: Automatically generates test cases using Kotest's Arb (arbitrary) generators. Great for pure functions.
Data-driven testing: withData allows parameterized test cases for multiple inputs.
Examples and custom generators available in references/code-examples.md.
Use beforeTest/afterTest for test-level setup/cleanup, and beforeSpec/afterSpec for suite-level initialization.
beforeSpec { db = setupDatabase() }
afterSpec { db.close() }
beforeTest { db.clear() }
Kotest extensions enable reusable test infrastructure. See references/code-examples.md for DatabaseExtension example.
// build.gradle.kts
plugins {
id("org.jetbrains.kotlinx.kover") version "0.9.7"
}
kover {
reports {
total {
html { onCheck = true }
xml { onCheck = true }
}
filters {
excludes {
classes("*.generated.*", "*.config.*")
}
}
verify {
rule {
minBound(80) // Fail build below 80% coverage
}
}
}
}
./gradlew koverHtmlReport # Generate HTML report
./gradlew koverVerify # Verify coverage meets thresholds
./gradlew koverXmlReport # Generate XML for CI
# View report (macOS)
open build/reports/kover/html/index.html
| Code Type | Target | |-----------|--------| | Critical business logic | 100% | | Public APIs | 90%+ | | General code | 80%+ | | Generated / config code | Exclude |
./gradlew test # Run all tests
./gradlew test --tests "com.example.UserServiceTest" # Run specific class
./gradlew test --tests "com.example.UserServiceTest.getUser*" # Run by pattern
./gradlew test --info # Verbose output
./gradlew koverHtmlReport # Tests + coverage report
./gradlew detekt # Static analysis
./gradlew ktlintCheck # Formatting check
./gradlew test --continuous # Watch mode
coEvery/coVerify — Never use every/verify for coroutines.runTest for coroutines — Never use Thread.sleep() in coroutine tests; use advanceTimeBy or advanceUntilIdle.data classes — Makes test intent clear and setup reusable.relaxed = true for loggers/observers — They're usually not critical to test assertions.advanceTimeBy or runTest scheduler control instead of delays.references/code-examples.md for StringSpec, BehaviorSpec, DescribeSpecreferences/code-examples.mdreferences/code-examples.mdreferences/code-examples.mdreferences/code-examples.mdreferences/code-examples.mdRemember: Tests are documentation. They show how your Kotlin code is meant to be used. Use Kotest's expressive matchers to make tests readable and MockK for clean mocking of dependencies.
development
Native Web UI structured renderer schemas for compose-block drafts, search-results cards, dataframe tables, chart-json charts, and diff output
tools
Unified search hub. Route any web/real-time/X lookup through a 4-tier escalation: built-in web search → cli-jaw browser CDP → progrok Grok OAuth → web-ai (Grok Expert / GPT Pro). Use for: search, 검색, web search, latest news, real-time info, X/Twitter, fact lookup, deep research.
development
UI/UX intent discovery, design vocabulary, product personalities, UX state patterns, typography line break judgment, favicon/product logo design, and logo trust section design. Use when user design direction is vague, when building onboarding/empty/error states, when setting up favicons or product logos, or when referencing a product aesthetic.
development
Canonical owner of module boundary rules, circular dependency detection/prevention, implicit coupling taxonomy, barrel/re-export discipline, and boundary-only defensive programming. Referenced by dev, dev-code-reviewer, dev-backend, dev-frontend stubs.