跳转至

Kotlin TDD 命令

此命令强制采用使用 Kotest、MockK 和 Kover 的 Kotlin 代码测试驱动开发方法论。

此命令的工作方式

  1. 定义类型/接口:先搭建函数签名
  2. 编写 Kotest 测试:创建全面的测试规格(RED)
  3. 运行测试:验证测试因正确原因而失败
  4. 实现代码:编写使测试通过的最小代码(GREEN)
  5. 重构:在保持测试绿色的同时改进
  6. 检查覆盖率:使用 Kover 确保 80% 以上的覆盖率

使用时机

使用 /kotlin-test 的情况: - 实现新的 Kotlin 函数或类时 - 为现有 Kotlin 代码添加测试覆盖率时 - 修复 bug 时(先编写失败的测试) - 构建重要业务逻辑时 - 学习 Kotlin TDD 工作流时

TDD 循环

RED     -> 失敗するKotestテストを書く
GREEN   -> テストを通す最小限のコードを実装
REFACTOR -> コードを改善、テストはグリーンのまま
REPEAT  -> 次のテストケースへ

会话示例

User: /kotlin-test ユーザー登録リクエストをバリデートする関数が必要です

Agent:
# TDDセッション: 登録バリデーター

## ステップ 1: インターフェース定義

```kotlin
// validator/RegistrationValidator.kt
package com.example.validator

data class RegistrationRequest(
    val name: String,
    val email: String,
    val password: String,
)

sealed class ValidationResult {
    data object Valid : ValidationResult()
    data class Invalid(val errors: List<String>) : ValidationResult()
}

fun validateRegistration(request: RegistrationRequest): ValidationResult {
    TODO("not implemented")
}
```

## ステップ 2: Kotestテストを書く(RED)

```kotlin
// validator/RegistrationValidatorTest.kt
package com.example.validator

import io.kotest.core.spec.style.FunSpec
import io.kotest.matchers.shouldBe
import io.kotest.matchers.types.shouldBeInstanceOf

class RegistrationValidatorTest : FunSpec({
    test("valid registration returns Valid") {
        val request = RegistrationRequest(
            name = "Alice",
            email = "alice@example.com",
            password = "SecureP@ss1",
        )

        val result = validateRegistration(request)

        result.shouldBeInstanceOf<ValidationResult.Valid>()
    }

    test("blank name returns Invalid") {
        val request = RegistrationRequest(
            name = "",
            email = "alice@example.com",
            password = "SecureP@ss1",
        )

        val result = validateRegistration(request)

        val invalid = result.shouldBeInstanceOf<ValidationResult.Invalid>()
        invalid.errors shouldBe listOf("Name is required")
    }

    test("invalid email returns Invalid") {
        val request = RegistrationRequest(
            name = "Alice",
            email = "not-an-email",
            password = "SecureP@ss1",
        )

        val result = validateRegistration(request)

        val invalid = result.shouldBeInstanceOf<ValidationResult.Invalid>()
        invalid.errors shouldBe listOf("Invalid email format")
    }

    test("short password returns Invalid") {
        val request = RegistrationRequest(
            name = "Alice",
            email = "alice@example.com",
            password = "short",
        )

        val result = validateRegistration(request)

        val invalid = result.shouldBeInstanceOf<ValidationResult.Invalid>()
        invalid.errors shouldBe listOf("Password must be at least 8 characters")
    }

    test("multiple errors returns all errors") {
        val request = RegistrationRequest(
            name = "",
            email = "bad",
            password = "short",
        )

        val result = validateRegistration(request)

        val invalid = result.shouldBeInstanceOf<ValidationResult.Invalid>()
        invalid.errors.size shouldBe 3
    }
})
```

## ステップ 3: テスト実行 - FAIL確認

```bash
$ ./gradlew test

RegistrationValidatorTest > valid registration returns Valid FAILED
  kotlin.NotImplementedError: An operation is not implemented

FAILED (5 tests, 0 passed, 5 failed)
```

✓ テストが期待通りに失敗(NotImplementedError)。

## ステップ 4: 最小限のコードを実装(GREEN)

```kotlin
// validator/RegistrationValidator.kt
package com.example.validator

private val EMAIL_REGEX = Regex("^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$")
private const val MIN_PASSWORD_LENGTH = 8

fun validateRegistration(request: RegistrationRequest): ValidationResult {
    val errors = buildList {
        if (request.name.isBlank()) add("Name is required")
        if (!EMAIL_REGEX.matches(request.email)) add("Invalid email format")
        if (request.password.length < MIN_PASSWORD_LENGTH) add("Password must be at least $MIN_PASSWORD_LENGTH characters")
    }

    return if (errors.isEmpty()) ValidationResult.Valid
    else ValidationResult.Invalid(errors)
}
```

## ステップ 5: テスト実行 - PASS確認

```bash
$ ./gradlew test

RegistrationValidatorTest > valid registration returns Valid PASSED
RegistrationValidatorTest > blank name returns Invalid PASSED
RegistrationValidatorTest > invalid email returns Invalid PASSED
RegistrationValidatorTest > short password returns Invalid PASSED
RegistrationValidatorTest > multiple errors returns all errors PASSED

PASSED (5 tests, 5 passed, 0 failed)
```

✓ 全テスト通過!

## ステップ 6: カバレッジチェック

```bash
$ ./gradlew koverHtmlReport

Coverage: 100.0% of statements
```

✓ カバレッジ: 100%

## TDD完了!

测试模式

StringSpec(最简单)

class CalculatorTest : StringSpec({
    "add two positive numbers" {
        Calculator.add(2, 3) shouldBe 5
    }
})

BehaviorSpec(BDD)

class OrderServiceTest : BehaviorSpec({
    Given("a valid order") {
        When("placed") {
            Then("should be confirmed") { /* ... */ }
        }
    }
})

数据驱动测试

class ParserTest : FunSpec({
    context("valid inputs") {
        withData("2026-01-15", "2026-12-31", "2000-01-01") { input ->
            parseDate(input).shouldNotBeNull()
        }
    }
})

协程测试

class AsyncServiceTest : FunSpec({
    test("concurrent fetch completes") {
        runTest {
            val result = service.fetchAll()
            result.shouldNotBeEmpty()
        }
    }
})

覆盖率命令

# カバレッジ付きでテスト実行
./gradlew koverHtmlReport

# カバレッジ閾値を検証
./gradlew koverVerify

# CI用XMLレポート
./gradlew koverXmlReport

# HTMLレポートを開く
open build/reports/kover/html/index.html

# 特定のテストクラスを実行
./gradlew test --tests "com.example.UserServiceTest"

# 詳細出力で実行
./gradlew test --info

覆盖率目标

代码类型 目标
关键业务逻辑 100%
公共 API 90% 以上
一般代码 80% 以上
生成代码 排除

TDD 最佳实践

应该做: - 在实现之前先编写测试 - 每次变更后运行测试 - 使用 Kotest 匹配器编写富有表现力的断言 - 对挂起函数使用 MockK 的 coEvery/coVerify - 测试行为而非实现细节 - 包含边界情况(空、null、最大值)

不应该做: - 在测试之前编写实现 - 跳过 RED 阶段 - 直接测试私有函数 - 在协程测试中使用 Thread.sleep() - 忽略不稳定测试

  • /kotlin-build — 修复构建错误
  • /kotlin-review — 实现后审查代码
  • verification-loop 技能 — 运行完整验证循环
  • 技能:skills/kotlin-testing/
  • 技能:skills/tdd-workflow/

本页原文 Markdown:在 AtomGit 查看·内容源自开源项目 ev/ECC