mirror of
https://github.com/affaan-m/everything-claude-code.git
synced 2026-06-14 04:01:30 +08:00
ec9ace9c54
Translate everything-claude-code repository to Japanese including: - 17 root documentation files - 60 agent documentation files - 80 command documentation files - 99 rule files across 18 language directories (common, angular, arkts, cpp, csharp, dart, fsharp, golang, java, kotlin, perl, php, python, ruby, rust, swift, typescript, web) - 199 skill documentation files Total: 455 files translated to Japanese with: - Consistent terminology glossary applied throughout - YAML field names preserved in English (name, description, etc.) - Code blocks and examples untouched (comments translated) - Markdown structure and relative links preserved - Professional translation maintaining technical accuracy This translation expands ECC accessibility to Japanese-speaking developers and teams. Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
309 lines
8.1 KiB
Markdown
309 lines
8.1 KiB
Markdown
---
|
|
description: RustにおけるTDDワークフローを強制します。テストを先に書き、その後に実装します。cargo-llvm-covで80%以上のカバレッジを検証します。
|
|
---
|
|
|
|
# Rust TDD コマンド
|
|
|
|
このコマンドは、`#[test]`、rstest、proptest、mockall を使用した Rust コードのテスト駆動開発手法を強制します。
|
|
|
|
## このコマンドの機能
|
|
|
|
1. **型/トレイトの定義**: `todo!()` で関数シグネチャをスキャフォールドする
|
|
2. **テストの作成**: 包括的なテストモジュールを作成する(RED)
|
|
3. **テストの実行**: テストが正しい理由で失敗することを確認する
|
|
4. **コードの実装**: テストを通過する最小限のコードを書く(GREEN)
|
|
5. **リファクタリング**: テストをグリーンに保ちながら改善する
|
|
6. **カバレッジの確認**: cargo-llvm-cov で80%以上のカバレッジを確保する
|
|
|
|
## 使用するタイミング
|
|
|
|
以下の場合に `/rust-test` を使用してください:
|
|
- 新しい Rust の関数、メソッド、トレイトを実装する場合
|
|
- 既存の Rust コードにテストカバレッジを追加する場合
|
|
- バグを修正する場合(先に失敗するテストを書く)
|
|
- 重要なビジネスロジックを構築する場合
|
|
- Rust での TDD ワークフローを学習する場合
|
|
|
|
## TDD サイクル
|
|
|
|
```
|
|
RED -> 先に失敗するテストを書く
|
|
GREEN -> テストを通過する最小限のコードを実装する
|
|
REFACTOR -> コードを改善し、テストはグリーンを維持する
|
|
REPEAT -> 次のテストケースへ
|
|
```
|
|
|
|
## セッション例
|
|
|
|
````text
|
|
User: /rust-test ユーザー登録を検証する関数が必要です
|
|
|
|
エージェント:
|
|
# TDD セッション: 登録バリデーター
|
|
|
|
## ステップ 1: インターフェースの定義
|
|
|
|
```rust
|
|
// src/validator.rs
|
|
pub struct RegistrationRequest {
|
|
pub name: String,
|
|
pub email: String,
|
|
pub password: String,
|
|
}
|
|
|
|
pub enum ValidationResult {
|
|
Valid,
|
|
Invalid(Vec<String>),
|
|
}
|
|
|
|
pub fn validate_registration(request: &RegistrationRequest) -> ValidationResult {
|
|
todo!()
|
|
}
|
|
```
|
|
|
|
## ステップ 2: テストの作成(RED)
|
|
|
|
```rust
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn valid_registration_returns_valid() {
|
|
let request = RegistrationRequest {
|
|
name: "Alice".into(),
|
|
email: "alice@example.com".into(),
|
|
password: "SecureP@ss1".into(),
|
|
};
|
|
assert!(matches!(validate_registration(&request), ValidationResult::Valid));
|
|
}
|
|
|
|
#[test]
|
|
fn blank_name_returns_invalid() {
|
|
let request = RegistrationRequest {
|
|
name: "".into(),
|
|
email: "alice@example.com".into(),
|
|
password: "SecureP@ss1".into(),
|
|
};
|
|
match validate_registration(&request) {
|
|
ValidationResult::Invalid(errors) => {
|
|
assert!(errors.contains(&"Name is required".to_string()));
|
|
}
|
|
ValidationResult::Valid => panic!("expected Invalid"),
|
|
}
|
|
}
|
|
|
|
#[test]
|
|
fn invalid_email_returns_invalid() {
|
|
let request = RegistrationRequest {
|
|
name: "Alice".into(),
|
|
email: "not-an-email".into(),
|
|
password: "SecureP@ss1".into(),
|
|
};
|
|
assert!(matches!(
|
|
validate_registration(&request),
|
|
ValidationResult::Invalid(_)
|
|
));
|
|
}
|
|
|
|
#[test]
|
|
fn short_password_returns_invalid() {
|
|
let request = RegistrationRequest {
|
|
name: "Alice".into(),
|
|
email: "alice@example.com".into(),
|
|
password: "short".into(),
|
|
};
|
|
assert!(matches!(
|
|
validate_registration(&request),
|
|
ValidationResult::Invalid(_)
|
|
));
|
|
}
|
|
}
|
|
```
|
|
|
|
## ステップ 3: テストの実行 — 失敗を確認
|
|
|
|
```bash
|
|
$ cargo test
|
|
running 4 tests
|
|
test tests::valid_registration_returns_valid ... FAILED (not yet implemented)
|
|
test tests::blank_name_returns_invalid ... FAILED
|
|
test tests::invalid_email_returns_invalid ... FAILED
|
|
test tests::short_password_returns_invalid ... FAILED
|
|
```
|
|
|
|
テストは想定通り失敗しました(todo! パニック)。
|
|
|
|
## ステップ 4: 最小限のコードを実装(GREEN)
|
|
|
|
```rust
|
|
pub fn validate_registration(request: &RegistrationRequest) -> ValidationResult {
|
|
let mut errors = Vec::new();
|
|
|
|
if request.name.trim().is_empty() {
|
|
errors.push("Name is required".into());
|
|
}
|
|
if !request.email.contains('@') {
|
|
errors.push("Invalid email format".into());
|
|
}
|
|
if request.password.len() < 8 {
|
|
errors.push("Password must be at least 8 characters".into());
|
|
}
|
|
|
|
if errors.is_empty() {
|
|
ValidationResult::Valid
|
|
} else {
|
|
ValidationResult::Invalid(errors)
|
|
}
|
|
}
|
|
```
|
|
|
|
## ステップ 5: テストの実行 — 成功を確認
|
|
|
|
```bash
|
|
$ cargo test
|
|
running 4 tests
|
|
test tests::valid_registration_returns_valid ... ok
|
|
test tests::blank_name_returns_invalid ... ok
|
|
test tests::invalid_email_returns_invalid ... ok
|
|
test tests::short_password_returns_invalid ... ok
|
|
|
|
test result: ok. 4 passed; 0 failed
|
|
```
|
|
|
|
すべてのテストが成功しました!
|
|
|
|
## ステップ 6: カバレッジの確認
|
|
|
|
```bash
|
|
$ cargo llvm-cov
|
|
Coverage: 100.0% of lines
|
|
```
|
|
|
|
カバレッジ: 100%
|
|
|
|
## TDD 完了!
|
|
````
|
|
|
|
## テストパターン
|
|
|
|
### ユニットテスト
|
|
|
|
```rust
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
#[test]
|
|
fn adds_two_numbers() {
|
|
assert_eq!(add(2, 3), 5);
|
|
}
|
|
|
|
#[test]
|
|
fn handles_error() -> Result<(), Box<dyn std::error::Error>> {
|
|
let result = parse_config(r#"port = 8080"#)?;
|
|
assert_eq!(result.port, 8080);
|
|
Ok(())
|
|
}
|
|
}
|
|
```
|
|
|
|
### rstest によるパラメータ化テスト
|
|
|
|
```rust
|
|
use rstest::{rstest, fixture};
|
|
|
|
#[rstest]
|
|
#[case("hello", 5)]
|
|
#[case("", 0)]
|
|
#[case("rust", 4)]
|
|
fn test_string_length(#[case] input: &str, #[case] expected: usize) {
|
|
assert_eq!(input.len(), expected);
|
|
}
|
|
```
|
|
|
|
### 非同期テスト
|
|
|
|
```rust
|
|
#[tokio::test]
|
|
async fn fetches_data_successfully() {
|
|
let client = TestClient::new().await;
|
|
let result = client.get("/data").await;
|
|
assert!(result.is_ok());
|
|
}
|
|
```
|
|
|
|
### プロパティベーステスト
|
|
|
|
```rust
|
|
use proptest::prelude::*;
|
|
|
|
proptest! {
|
|
#[test]
|
|
fn encode_decode_roundtrip(input in ".*") {
|
|
let encoded = encode(&input);
|
|
let decoded = decode(&encoded).unwrap();
|
|
assert_eq!(input, decoded);
|
|
}
|
|
}
|
|
```
|
|
|
|
## カバレッジコマンド
|
|
|
|
```bash
|
|
# サマリーレポート
|
|
cargo llvm-cov
|
|
|
|
# HTMLレポート
|
|
cargo llvm-cov --html
|
|
|
|
# しきい値を下回った場合に失敗
|
|
cargo llvm-cov --fail-under-lines 80
|
|
|
|
# 特定のテストを実行
|
|
cargo test test_name
|
|
|
|
# 出力付きで実行
|
|
cargo test -- --nocapture
|
|
|
|
# 最初の失敗で停止しない
|
|
cargo test --no-fail-fast
|
|
```
|
|
|
|
## カバレッジ目標
|
|
|
|
| コードの種類 | 目標 |
|
|
|-----------|--------|
|
|
| 重要なビジネスロジック | 100% |
|
|
| パブリック API | 90%以上 |
|
|
| 一般的なコード | 80%以上 |
|
|
| 生成コード / FFI バインディング | 除外 |
|
|
|
|
## TDD ベストプラクティス
|
|
|
|
**すべきこと:**
|
|
- 実装の前にまずテストを書く
|
|
- 変更のたびにテストを実行する
|
|
- より良いエラーメッセージのために `assert!` よりも `assert_eq!` を使用する
|
|
- よりクリーンな出力のために `Result` を返すテストで `?` を使用する
|
|
- 実装ではなく振る舞いをテストする
|
|
- エッジケースを含める(空、境界値、エラーパス)
|
|
|
|
**すべきでないこと:**
|
|
- テストの前に実装を書く
|
|
- RED フェーズをスキップする
|
|
- `Result::is_err()` で対応できる場合に `#[should_panic]` を使用する
|
|
- テストで `sleep()` を使用する — チャネルまたは `tokio::time::pause()` を使用する
|
|
- すべてをモック化する — 可能な場合は統合テストを優先する
|
|
|
|
## 関連コマンド
|
|
|
|
- `/rust-build` - ビルドエラーの修正
|
|
- `/rust-review` - 実装後のコードレビュー
|
|
- `verification-loop` スキル - 完全な検証ループの実行
|
|
|
|
## 関連
|
|
|
|
- スキル: `skills/rust-testing/`
|
|
- スキル: `skills/rust-patterns/`
|