KINTO Tech Blog
General

AI時代の新しい開発手法「TDD × AI」を始めよう

Cover Image for AI時代の新しい開発手法「TDD × AI」を始めよう

AIが急速に進化する2025年、エンジニアにとって「AIをどう活用するか」が重要なスキルとなってきました。

しかし、AIを効果的に活用するには、適切なプロンプト(指示の出し方)を理解する必要があり、そのためには 慣れや知見 が不可欠です。

そこで、AIとコーディングを行う最初のステップとして、今回のテーマである TDD(test-driven development: テスト駆動開発) と AI を活用した開発を紹介します。

TDD × AIのメリット

実装コストが激減!エンジニアは"テストを書くだけ"でOK
テストを書くだけで、複雑な指示もプロンプトも不要。あとはAIが自動でコードを生成。

開発速度が爆速化!細かな往復が劇的に減少
TDDのステップごとにAIが即座にコードを生成するので、開発効率が驚異的にアップ。

圧倒的なコード品質!テストでしっかりAIの暴走をコントロール
明確なテストでAIの生成コードをしっかり制御。結果的にバグの少ないコードになる。

TDDとは?

大前提となるTDD(Test-Driven Development: テスト駆動開発)について簡単に説明します。

chart1

https://www.amazon.co.jp/dp/4274217884

「TDD(Test-Driven Development: テスト駆動開発)」はKent Beck氏が👆の書籍で20年以上前に提唱した手法です。
上の図の「まずテストを書いて、次にテストを通過する実装をする、最後にリファクタリング」というシンプルなサイクルを繰り返すことで、品質の高いコードを生み出すことができます。
また、テストが実装の起点になるので、テスタブルな構造を担保しつつ、実装を進めることが出来ます。

TDDを実践する

https://code.visualstudio.com/docs/copilot/copilot-edits#_use-agent-mode-preview

今回の方法では、エンジニアがテストを書き、生成AIが実装・リファクタリングを担うことで、コード品質を維持しつつ効率的に開発を進めます。

chart2

今回は パスワードのバリデーション を例に、TDD × AIの流れを説明していきます。

まずは、文字数のバリデーション から始めていきましょう。

ステップ1: 文字数バリデーションテストの作成

対象になるPasswordバリデーションのクラスとテストファイルを用意しましょう。
この段階ではどちらも空のファイルで問題ありません。

ファイルが作成できたらそのままPasswordバリデーションクラスを書きたくなるところですが、今回はTDDなのでテストを書いていきます。

PasswordValidatorTests.swift
@Test("パスワードの文字数が8文字以上16文字以下でバリデーションが成功すること")
func testPasswordLengthValidation() async throws {
    let sut = PasswordValidator()
    let validPasswordShort = "Valid123"
    let validPasswordLong = "ValidPassword123"
    let invalidPasswordShort = "Short01"
    let invalidPasswordLong = "ThisPasswordIsWay"

    #expect(sut.validate(validPasswordShort) == true)
    #expect(sut.validate(validPasswordLong) == true)
    #expect(sut.validate(invalidPasswordShort) == false)
    #expect(sut.validate(invalidPasswordLong) == false)
}

この段階では PasswordValidator クラスや validate メソッドが未実装のため、当然エラーが発生します。

次に、AIにプロンプトを入力して実装を依頼します。

input prompt

すると、数十秒後にAIが実装を生成してくれます。

PasswordValidator.swift
struct PasswordValidator {
    // パスワードの長さの制約を定数として定義
    private let minimumPasswordLength = 8
    private let maximumPasswordLength = 16

    /// パスワードが有効かどうかを検証します
    /// - Parameter password: 検証するパスワード
    /// - Returns: パスワードが有効な場合はtrue、そうでない場合はfalse
    func validate(_ password: String) -> Bool {
        let passwordLength = password.count
        return passwordLength >= minimumPasswordLength && passwordLength <= maximumPasswordLength
    }
}

次に、数字・文字・記号のミックス判定を追加してみます。

ステップ2: 数字、文字、記号の含有バリデーションの追加

PasswordValidatorTests.swift
@Test("パスワードの文字列の中に数字、文字、記号が含まれている場合にバリデーションが成功すること")
func testPasswordCharacterValidation() async throws {
    let sut = PasswordValidator()
    let validPassword = "ValidPassword12!"
    let invalidPasswordNoNumber = "InvalidPassword!"
    let invalidPasswordNoCharacter = "1234567890!"
    let invalidPasswordNoSymbol = "InvalidPassword1"

    #expect(sut.validate(validPassword) == true)
    #expect(sut.validate(invalidPasswordNoNumber) == false)
    #expect(sut.validate(invalidPasswordNoCharacter) == false)
    #expect(sut.validate(invalidPasswordNoSymbol) == false)
}

この段階でエラーが発生しますが、気にせずテストケースをAIに渡して実装を生成します。

PasswordValidator.swift
struct PasswordValidator {
    // パスワードの長さの制約を定数として定義
    private let minimumPasswordLength = 8
    private let maximumPasswordLength = 16

    /// パスワードが有効かどうかを検証します
    /// - Parameter password: 検証するパスワード
    /// - Returns: パスワードが有効な場合はtrue、そうでない場合はfalse
    func validate(_ password: String) -> Bool {
        let passwordLength = password.count
        guard passwordLength >= minimumPasswordLength && passwordLength <= maximumPasswordLength
        else {
            return false
        }

        let hasNumber = password.rangeOfCharacter(from: .decimalDigits) != nil
        let hasLetter = password.rangeOfCharacter(from: .letters) != nil
        let hasSymbol =
            password.rangeOfCharacter(from: .symbols) != nil
            || password.rangeOfCharacter(from: .punctuationCharacters) != nil

        return hasNumber && hasLetter && hasSymbol
    }
}

ここまで10分もかからず実装できました。

通常のコーディングではプロンプトに色々な条件や仕様を伝える必要がありますが、この方法では テスト条件を満たした実装をして というお願いをするだけです。
実装内容に関してはTestに全て書かれているので、複雑なプロンプトの指定はほぼ不要になります。

AIとのコミュニケーションをさらに効率化するには

実装のルールや制約を事前に「copilot-instructions.md」に書いておけば、毎回AIに細かい指示を伝える必要もありません。

.github/copilot-instructions.md
日本語で返答してください。

### コーディングルール

- テストはswift-testingを使用してください。
- 実装には基本的にマジックナンバーは使わないこと
- DRYの原則に則って実装してください
- KISSの原則に則って実装してください
- YAGNIの原則に則って実装してください

AI時代に活躍するエンジニアになるために

AIは万能ではありません。しかし、だからといって諦めるのはとてももったいないです!
「AIが得意なこと」と「人間が担うべきこと」を冷静に見極めること が重要です。
「TDD × AI」で、AIコーディングの癖を理解し、次世代の開発スピードと品質を手に入れましょう🚀

Facebook

関連記事 | Related Posts

イベント情報

P3NFEST Bug Bounty 2025 Winter 【KINTOテクノロジーズ協賛】