0Pricing
Kotlin Academy · レッスン

ユーザーを壊さずにDSLをテスト・進化させる

安定性を考慮してDSL APIを設計し、読みやすいアサーションブロックでテストします。

「ユーザーを壊さずにDSLをテスト・進化させる」はCoddyKit上の無料Kotlin Academyレッスンです。 これはレッスン4/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはKotlin Academy学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Kotlin Academyコースには全4レッスンが含まれています。

DSLのテストが異なる理由

DSLは公開APIです。その変更によって、ユーザーコード内のすべての呼び出し側が壊れる可能性があります。DSLのテストでは、生成される出力と、適用される構造の両方を検証する必要があります。無効な構成が引き続きコンパイルエラーになることも含まれます。

DSLの出力をテストする

最も簡単なテストは、DSLを使ってオブジェクトを構築し、レンダリング結果またはビルダーの内部状態を検証することです。

@Test
fun `div contains a paragraph`() {
    val result = html {
        body {
            div { p("Hi") }
        }
    }
    assertTrue(result.render().contains("<p>"))
}

ビルダーの状態をテストする

レンダリングされた文字列をテストする代わりに、ビルダーのオブジェクトグラフを直接テストします。これにより、フォーマットの変更に対してより堅牢になります。

@Test
fun `server config has correct port`() {
    val cfg = server {
        host = "example.com"
        port = 9090
    }
    assertEquals(9090, cfg.port)
    assertEquals("example.com", cfg.host)
}

ネストした構造をテストする

オブジェクトツリーをたどり、ネスト関係を検証します。

@Test
fun `body contains one div`() {
    val page = html { body { div { } } }
    assertEquals(1, page.children
        .filterIsInstance<Body>().first()
        .children.filterIsInstance<Div>().size
    )
}

コンパイルエラーのテスト

コンパイルエラーを直接ユニットテストすることはできませんが、失敗するコードをコメントアウトし、// This should NOT compileのようなコメントを追加できます。プロジェクトによっては、Kotlin Compile Testingライブラリを使って、特定のコードがコンパイルされないことを検証します。

DSLを安全に進化させる:追加的な変更

デフォルト値を持つ新しいオプションパラメータや、新しいビルダー関数の追加は、後方互換性があります。既存の呼び出し側は変更せずにコンパイルできます。

// Before
fun server(block: ServerConfig.() -> Unit): ServerConfig
// After — additive: new optional feature
fun server(enableMetrics: Boolean = false, block: ServerConfig.() -> Unit): ServerConfig

破壊的変更:削除または名前変更

DSL関数を削除または名前変更すると、呼び出し側が壊れます。名前を変更する必要がある場合は、非推奨のエイリアスを提供し、将来のメジャーバージョンで削除してください。

@Deprecated("Use database{} instead", ReplaceWith("database(block)"))
fun db(block: DbConfig.() -> Unit) = database(block)

DSLのバージョン管理

ライブラリとして提供するDSLでは、セマンティックバージョニングに従ってください。DSLの破壊的変更(関数の削除やレシーバー型の変更)には、メジャーバージョンの更新が必要です。変更内容は変更履歴に記載してください。

実験的なDSL機能に@RequiresOptInを使用する

不安定なDSL拡張には@RequiresOptInを付けます。ユーザーが明示的にオプトインするため、変更される可能性のある機能に誤って依存することを防げます。

@RequiresOptIn(message = "This DSL feature is experimental and may change")
annotation class ExperimentalDsl

@ExperimentalDsl
fun ServerConfig.enableDebug() { /*...*/ }

DSLでのプロパティ委譲

DSLではプロパティ委譲を使用して必須フィールドを強制し、必須の値が不足している場合に分かりやすいエラーメッセージを提供できます。

class Required<T> {
    private var value: T? = null
    operator fun getValue(t: Any?, p: KProperty<*>): T = value ?: error("${p.name} is required")
    operator fun setValue(t: Any?, p: KProperty<*>, v: T) { value = v }
}

バージョンをまたぐコントラクトテスト

「ゴールデン」DSL使用例をテストとして一式保持します。リファクタリングによってそれらが壊れた場合、ユーザーが気付く前にテストスイートが検出します。これらは生きたドキュメントとしても機能します。

クイックチェック

後方互換性を保つうえで最も安全なDSLの変更はどのようなものですか?

まとめ:DSLのテストと進化

主なポイント:

  • ユニットテストでDSLの出力とビルダーのオブジェクト状態をテストする
  • 追加的な変更(新しいオプション関数やパラメータ)は安全である
  • @Deprecated(ReplaceWith=...)を使って、ユーザーを壊さずに名前を変更する
  • 実験的なDSL機能には@RequiresOptInを使用する
  • バージョン間の回帰を検出するため、ゴールデン使用例のテストを保持する

よくある質問

「ユーザーを壊さずにDSLをテスト・進化させる」レッスンは無料ですか?

はい。「ユーザーを壊さずにDSLをテスト・進化させる」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Kotlin Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Kotlin Academyコースには全4レッスンが含まれています。

「ユーザーを壊さずにDSLをテスト・進化させる」で何を学びますか?

安定性を考慮してDSL APIを設計し、読みやすいアサーションブロックでテストします。 ブラウザで直接実行するハンズオンコードでKotlin Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。

Kotlin Academyを始めるのに経験は必要ですか?

事前経験は必要ありません。CoddyKitのKotlin Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン4/4です。

「ユーザーを壊さずにDSLをテスト・進化させる」レッスンにはどのくらい時間がかかりますか?

ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。

このKotlin Academyレッスンでコードを書いて実行できますか?

はい。すべてのKotlin Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. レシーバー付きLambda:DSLの基盤
  2. @DslMarker:レシーバーの漏洩を防ぐ
  3. 型安全なHTML/Config DSLの構築
  4. ユーザーを壊さずにDSLをテスト・進化させる
← Kotlin Academyに戻る