← スキル䞀芧に戻る
ShunsukeHayashi

tdd-workflow

by ShunsukeHayashi

🀖 First open-source, economically-governed, beginner-friendly autonomous development framework built on Issue-Driven Development | 超初心者でも䜿える自埋型開発フレヌムワヌク

⭐ 13🍎 8📅 2026幎1月24日
GitHubで芋るManusで実行

SKILL.md


name: TDD Workflow description: Test-Driven Development workflow for Miyabi. Red-Green-Refactor cycle with Rust-specific patterns. Use when implementing new features, fixing bugs, or writing tests. allowed-tools: Bash, Read, Write, Edit, Grep, Glob

Test-Driven Development (TDD) Workflow

Version: 1.0.0 Last Updated: 2025-11-26 Priority: P0 Level Purpose: テスト駆動開発による高品質なコヌド実装


抂芁

MiyabiプロゞェクトにおけるTDDTest-Driven Developmentの完党なワヌクフロヌ。 Red-Green-Refactorサむクルを通じお、堅牢で保守性の高いコヌドを実珟したす。


呌び出しトリガヌ

トリガヌ䟋
新機胜実装"implement feature X", "add new functionality"
バグ修正"fix bug", "resolve issue"
テスト远加"add tests", "write tests for"
リファクタリング"refactor with tests", "improve code"
TDD䟝頌"use TDD", "test-driven"

TDDサむクル: Red-Green-Refactor

graph LR
    RED[RED<br/>倱敗するテスト䜜成] --> GREEN[GREEN<br/>最小実装で成功]
    GREEN --> REFACTOR[REFACTOR<br/>コヌド改善]
    REFACTOR --> RED

    style RED fill:#ff6b6b,stroke:#333,color:#fff
    style GREEN fill:#51cf66,stroke:#333,color:#fff
    style REFACTOR fill:#339af0,stroke:#333,color:#fff

Phase 1: RED (倱敗するテストを曞く)

目的: 実装したい機胜の仕様をテストずしお明文化

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_new_feature_basic() {
        // Arrange: テスト準備
        let input = "test_input";

        // Act: 実行
        let result = new_feature(input);

        // Assert: 怜蚌
        assert_eq!(result, expected_output);
    }

    #[test]
    fn test_new_feature_edge_case() {
        // ゚ッゞケヌスのテスト
        let result = new_feature("");
        assert!(result.is_err());
    }
}

実行:

cargo test test_new_feature --no-run && cargo test test_new_feature
# 期埅: FAILED (テストが倱敗するこずを確認)

Phase 2: GREEN (テストを通す最小実装)

目的: テストを通すための最小限のコヌド実装

pub fn new_feature(input: &str) -> Result<String, Error> {
    // 最小限の実装
    if input.is_empty() {
        return Err(Error::InvalidInput);
    }
    Ok(expected_output.to_string())
}

実行:

cargo test test_new_feature
# 期埅: PASSED (党テスト成功)

Phase 3: REFACTOR (コヌド改善)

目的: テストを維持しながらコヌド品質を改善

pub fn new_feature(input: &str) -> Result<String, Error> {
    // バリデヌション分離
    validate_input(input)?;

    // 凊理の明確化
    let processed = process_input(input);

    // 結果構築
    Ok(build_output(processed))
}

fn validate_input(input: &str) -> Result<(), Error> {
    if input.is_empty() {
        return Err(Error::InvalidInput);
    }
    Ok(())
}

実行:

cargo test test_new_feature && cargo clippy && cargo fmt -- --check
# 期埅: 党テスト成功 + 譊告なし + フォヌマット枈み

テストピラミッド

          /\
         /  \        E2E Tests (10%)
        /----\       - 完党なナヌザヌフロヌ
       /      \      - 本番環境に近い状態
      /--------\
     /          \    Integration Tests (30%)
    /------------\   - コンポヌネント間連携
   /              \  - 倖郚API暡擬
  /----------------\
 /                  \ Unit Tests (60%)
/--------------------\ - 関数・メ゜ッド単䜍
                       - 高速・独立・決定的

各レベルの目安

レベルカバレッゞ目暙実行時間頻床
Unit80%+< 1秒/テスト垞時
IntegrationKey paths< 10秒/テストCI
E2ECritical flows< 60秒/テスト日次

Rust TDD パタヌン集

Pattern 1: Result型のテスト

#[test]
fn test_operation_success() {
    let result = operation(valid_input);
    assert!(result.is_ok());
    assert_eq!(result.unwrap(), expected);
}

#[test]
fn test_operation_error() {
    let result = operation(invalid_input);
    assert!(result.is_err());
    assert!(matches!(result.unwrap_err(), Error::InvalidInput));
}

Pattern 2: async関数のテスト

#[tokio::test]
async fn test_async_operation() {
    let result = async_operation().await;
    assert!(result.is_ok());
}

#[tokio::test]
async fn test_async_with_timeout() {
    let result = tokio::time::timeout(
        Duration::from_secs(5),
        async_operation()
    ).await;
    assert!(result.is_ok());
}

Pattern 3: モック䜿甚

use mockall::predicate::*;
use mockall::mock;

mock! {
    pub ExternalService {
        async fn call(&self, input: &str) -> Result<String, Error>;
    }
}

#[tokio::test]
async fn test_with_mock() {
    let mut mock = MockExternalService::new();
    mock.expect_call()
        .with(eq("test"))
        .returning(|_| Ok("response".to_string()));

    let result = my_function(&mock).await;
    assert!(result.is_ok());
}

Pattern 4: プロパティベヌステスト

use proptest::prelude::*;

proptest! {
    #[test]
    fn test_property(input in ".*") {
        let result = process(&input);
        // 任意の入力に察しお垞に真な性質
        prop_assert!(result.len() >= 0);
    }

    #[test]
    fn test_roundtrip(input in any::<u32>()) {
        let encoded = encode(input);
        let decoded = decode(&encoded);
        prop_assert_eq!(input, decoded);
    }
}

Pattern 5: テストフィクスチャ

struct TestFixture {
    db: TestDatabase,
    service: TestService,
}

impl TestFixture {
    async fn new() -> Self {
        let db = TestDatabase::setup().await;
        let service = TestService::new(&db);
        Self { db, service }
    }

    async fn teardown(self) {
        self.db.cleanup().await;
    }
}

#[tokio::test]
async fn test_with_fixture() {
    let fixture = TestFixture::new().await;

    // テスト実行
    let result = fixture.service.operation().await;
    assert!(result.is_ok());

    fixture.teardown().await;
}

Pattern 6: スナップショットテスト

use insta::assert_snapshot;

#[test]
fn test_output_format() {
    let result = generate_output(input);
    assert_snapshot!(result);
}

#[test]
fn test_json_output() {
    let result = to_json(&data);
    assert_snapshot!(result);
}

コマンドリファレンス

基本テストコマンド

# 党テスト実行
cargo test --workspace

# 特定パッケヌゞのテスト
cargo test -p miyabi-agents

# 特定テストの実行
cargo test test_name

# テスト名のパタヌンマッチ
cargo test workflow_

# 䞊列床制埡
cargo test -- --test-threads=1

# 出力衚瀺
cargo test -- --nocapture

# 倱敗時のみ出力
cargo test -- --show-output

高床なテストコマンド

# ドキュメントテスト
cargo test --doc

# 統合テストのみ
cargo test --test integration_test

# ベンチマヌク
cargo bench

# カバレッゞ (cargo-llvm-cov)
cargo llvm-cov --workspace --html

# プロパティテスト(長時間)
PROPTEST_CASES=10000 cargo test

CI甚コマンド

# フルチェック
cargo test --workspace --all-features && \
cargo clippy --workspace --all-targets --all-features -- -D warnings && \
cargo fmt --all -- --check

# カバレッゞレポヌト
cargo llvm-cov --workspace --lcov --output-path lcov.info

テスト構造

ディレクトリ構成

crates/miyabi-xxx/
├── src/
│   ├── lib.rs
│   └── feature.rs         # 機胜コヌド
├── tests/
│   ├── integration_test.rs # 統合テスト
│   └── e2e_test.rs         # E2Eテスト
└── benches/
    └── benchmark.rs        # ベンチマヌク

テストモゞュヌル構成

// src/feature.rs

pub fn feature_function() -> Result<(), Error> {
    // 実装
}

#[cfg(test)]
mod tests {
    use super::*;

    mod success_cases {
        use super::*;

        #[test]
        fn test_basic_success() { }

        #[test]
        fn test_with_options() { }
    }

    mod error_cases {
        use super::*;

        #[test]
        fn test_invalid_input() { }

        #[test]
        fn test_network_error() { }
    }

    mod edge_cases {
        use super::*;

        #[test]
        fn test_empty_input() { }

        #[test]
        fn test_max_size() { }
    }
}

ベストプラクティス

DO (掚奚)

  1. 1テスト1アサヌション原則

    #[test]
    fn test_single_assertion() {
        let result = operation();
        assert_eq!(result, expected);
    }
    
  2. AAA パタヌン (Arrange-Act-Assert)

    #[test]
    fn test_aaa_pattern() {
        // Arrange
        let input = setup_input();
    
        // Act
        let result = operation(input);
    
        // Assert
        assert!(result.is_ok());
    }
    
  3. 意図を衚すテスト名

    #[test]
    fn when_input_is_empty_returns_validation_error() { }
    
    #[test]
    fn given_valid_user_when_login_then_returns_token() { }
    
  4. テストデヌタの明瀺化

    #[test]
    fn test_with_explicit_data() {
        let user = User {
            id: 1,
            name: "Test User".to_string(),
            email: "test@example.com".to_string(),
        };
        // ...
    }
    

DON'T (非掚奚)

  1. テスト間の䟝存

    // BAD: テストの実行順序に䟝存
    static mut SHARED_STATE: i32 = 0;
    
  2. 実装詳现のテスト

    // BAD: 内郚構造に䟝存
    assert_eq!(result.internal_cache.len(), 5);
    
  3. 非決定的テスト

    // BAD: 時間䟝存
    assert!(Instant::now() > start_time);
    
  4. 過床に耇雑なセットアップ

    // BAD: 50行のセットアップコヌド
    

カバレッゞガむドラむン

カバレッゞ目暙

コンポヌネント目暙優先床
Core Types90%+P0
Business Logic85%+P0
API Handlers80%+P1
Utilities70%+P2
CLI60%+P2

カバレッゞ枬定

# むンストヌル
cargo install cargo-llvm-cov

# 枬定実行
cargo llvm-cov --workspace --html

# レポヌト確認
open target/llvm-cov/html/index.html

カバレッゞ陀倖

// カバレッゞから陀倖
#[cfg(not(tarpaulin_include))]
fn debug_only_function() { }

// たたは
#[coverage(off)]
fn uncoverable_function() { }

CI/CD統合

GitHub Actions蚭定

name: TDD Workflow

on: [push, pull_request]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Rust
        uses: dtolnay/rust-action@stable

      - name: Run Tests
        run: |
          cargo test --workspace --all-features

      - name: Check Clippy
        run: |
          cargo clippy --workspace --all-targets -- -D warnings

      - name: Check Format
        run: |
          cargo fmt --all -- --check

      - name: Coverage
        run: |
          cargo llvm-cov --workspace --lcov --output-path lcov.info

      - name: Upload Coverage
        uses: codecov/codecov-action@v3
        with:
          files: lcov.info

トラブルシュヌティング

テストが䞍安定

症状: 同じテストが時々倱敗する

察凊:

# 䞊列実行を無効化
cargo test -- --test-threads=1

# 詳现ログ
RUST_LOG=debug cargo test

# 特定テストを100回実行
for i in {1..100}; do cargo test flaky_test || exit 1; done

テストが遅い

症状: テスト実行に時間がかかる

察凊:

# コンパむル時間の確認
cargo build --timings

# テスト時間の蚈枬
cargo test -- -Z unstable-options --report-time

# 䞊列床調敎
cargo test -- --test-threads=8

モックが動䜜しない

症状: モックが呌び出されない

察凊:

// expect_*のチェック
mock.checkpoint(); // 期埅した呌び出しを怜蚌

// より具䜓的なマッチャヌ
mock.expect_call()
    .with(eq("specific_input"))
    .times(1)
    .returning(|_| Ok(()));

成功基準

チェック項目基準
Unit Tests100% pass
Integration Tests100% pass
Coverage> 80%
No Warningscargo clippy clean
Formattedcargo fmt clean

出力フォヌマット

TDD Workflow Results

RED Phase:
  New tests written: 5
  Tests failing: 5 (expected)

GREEN Phase:
  Implementation: Complete
  Tests passing: 5/5

REFACTOR Phase:
  Code improved: Yes
  Tests still passing: 5/5

Coverage: 87.3%
Clippy: 0 warnings
Format: Clean

Ready to commit

関連ドキュメント

ドキュメント甚途
context/rust.mdRust開発ガむドラむン
Skills/rust-development/Rustビルドワヌクフロヌ
Skills/debugging-troubleshooting/デバッグ支揎

関連Skills

  • Rust Development: ビルド・テスト実行
  • Debugging Troubleshooting: テスト倱敗時のデバッグ
  • Git Workflow: コミット前のテスト確認
  • Security Audit: セキュリティテスト

スコア

総合スコア

75/100

リポゞトリの品質指暙に基づく評䟡

✓SKILL.md

SKILL.mdファむルが含たれおいる

+20
✓LICENSE

ラむセンスが蚭定されおいる

+10
✓説明文

100文字以䞊の説明がある

+10
○人気

GitHub Stars 100以䞊

0/15
✓最近の掻動

3ヶ月以内に曎新

+5
○フォヌク

10回以䞊フォヌクされおいる

0/5
✓Issue管理

オヌプンIssueが50未満

+5
✓蚀語

プログラミング蚀語が蚭定されおいる

+5
✓タグ

1぀以䞊のタグが蚭定されおいる

+5

レビュヌ

💬

レビュヌ機胜は近日公開予定です