tdd-mastery について
JavaScript、Python、Go でテスト駆動開発を行う開発者向けのテストスキルガイドです。テスト構成、カバレッジ、モック、アンチパターンも扱います。
主な機能
- 01Red-Green-Refactor サイクル
- 02Arrange-Act-Assert 構成
- 03Jest と Vitest のパターン
- 04pytest と Go のテストパターン
- 05カバレッジとテストレベルの指針
- 06モックの原則とアンチパターン
活用シーン
- 01実装前のテスト計画
- 02対応言語ごとのテスト構成
- 03カバレッジと不安定なテスト対応の確認
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ rohitg00/ awesome-claude-code-toolkit --skill tdd-masteryインストール後、Claude Code で/tdd-masteryを入力して読み込まれたか確認します。
詳細
TDD の習熟
基本サイクル:レッド・グリーン・リファクタリング
- レッド - 望ましい動作を定義する、失敗するテストを書きます
- グリーン - テストを通すために必要な最小限のコードを書きます
- リファクタリング - テストを通したままコードを整理します
まず失敗するテストを書かずに、本番コードを書いてはいけません。各サイクルは 2~10 分で行います。
テストの構成
Arrange-Act-Assert パターンを一貫して使います:
Arrange: Set up test data and dependencies
Act: Execute the behavior under test
Assert: Verify the expected outcome
テストには test_<unit>_<scenario>_<expected_result> または it("should <behavior> when <condition>") の形式で名前を付けます。
Jest / Vitest のパターン
describe("OrderService", () => {
it("should apply discount when order exceeds threshold", () => {
const order = createOrder({ items: [{ price: 150, qty: 1 }] });
const result = applyDiscount(order, { threshold: 100, percent: 10 });
expect(result.total).toBe(135);
});
it("should throw when applying discount to empty order", () => {
const order = createOrder({ items: [] });
expect(() => applyDiscount(order, defaultDiscount)).toThrow(EmptyOrderError);
});
});
モックには vi.fn() / jest.fn() を使います。モジュールのモック化より、依存性注入を優先します。共通のセットアップには beforeEach を使い、テスト間で変更可能な状態を共有しないでください。
pytest のパターン
@pytest.fixture
def db_session():
session = create_test_session()
yield session
session.rollback()
def test_create_user_stores_hashed_password(db_session):
user = UserService(db_session).create(email="[email protected]", password="secret")
assert user.password_hash != "secret"
assert verify_password("secret", user.password_hash)
@pytest.mark.parametrize("input,expected", [
("", False),
("short", False),
("ValidPass1!", True),
])
def test_password_validation(input, expected):
assert validate_password(input) == expected
例外には pytest.raises を使います。共通のフィクスチャには conftest.py を使います。時間のかかるテストには @pytest.mark.slow を付けます。
Go のテストパターン
func TestParseConfig(t *testing.T) {
tests := []struct {
name string
input string
want Config
wantErr bool
}{
{"valid yaml", "port: 8080", Config{Port: 8080}, false},
{"empty input", "", Config{}, true},
{"invalid port", "port: -1", Config{}, true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := ParseConfig([]byte(tt.input))
if (err != nil) != tt.wantErr {
t.Errorf("ParseConfig() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !tt.wantErr && got != tt.want {
t.Errorf("ParseConfig() = %v, want %v", got, tt.want)
}
})
}
}
通常はテーブル駆動テストを使います。テスト用のユーティリティ関数では t.Helper() を使います。チームですでに使用している場合に限り、testify/assert を使います。
テストレベル
| レベル | 範囲 | 速度 | 依存関係 |
|---|---|---|---|
| 単体 | 単一の関数/クラス | <100ms | なし(すべてモック化) |
| 統合 | モジュール間の境界 | <5s | 実際の DB、実際のファイルシステム |
| E2E | ユーザーフロー全体 | <30s | フルスタック |
目標比率:単体 70%、統合 20%、E2E 10%。
カバレッジのルール
- CI でラインカバレッジ 80%以上を必須にします
- ラインカバレッジだけでなく、ブランチカバレッジも追跡します
- 生成コード、型定義、設定ファイルは対象から除外します
- カバレッジの数値を満たすためだけにテストを書かず、動作をテストします
# Jest/Vitest
vitest run --coverage --coverage.thresholds.lines=80 --coverage.thresholds.branches=75
# pytest
pytest --cov=src --cov-fail-under=80 --cov-branch
# Go
go test -coverprofile=cover.out -coverpkg=./... ./...
go tool cover -func=cover.out
モックのガイドライン
- 境界でモック化します:HTTP クライアント、データベース、ファイルシステム、時計
- テスト対象のユニットはモック化しません
- リポジトリには、モックよりフェイク(インメモリ実装)を優先します
- モックの呼び出し回数ではなく、動作を検証します
t.Cleanup/afterEachを使って共有モックをリセットします
避けるべきアンチパターン
- 動作ではなく実装の詳細をテストする
- コードを削除しても通るテスト(同語反復的なテスト)
- テストケース間で変更可能な状態を共有する
- 不安定なテストを修正せずに放置する
- 非公開メソッドを直接テストする
- 意図を分かりにくくする、巨大なテストのセットアップ
コメント
Markdown 対応