코드리뷰리팩토링테스트by affaan-m
Rust TDD 명령어
Rust 프로젝트에 TDD(테스트 주도 개발) 워크플로를 적용하고, 테스트를 먼저 작성한 후 구현하도록 돕습니다. cargo-llvm-cov를 사용하여 80% 이상의 코드 커버리지를 검증합니다.
한 줄 평가 — 다음 사람 도와주세요
언제 쓰나
Rust 프로젝트에서 TDD(테스트 주도 개발) 원칙을 엄격하게 지키고, 테스트를 먼저 작성한 후 구현을 진행하며, 코드 커버리지를 80% 이상으로 유지하고 싶을 때 사용합니다.
SKILL.md
Lattice 한국어 번역 · 원본 affaan-m/everything-claude-code (841beea). 복사 → 저장하면 Claude Code가 인식합니다.
---
description: Rust를 위한 TDD 워크플로우를 강제합니다. 먼저 테스트를 작성하고, 그다음 구현합니다. cargo-llvm-cov로 80% 이상의 커버리지를 검증합니다.
---
# Rust TDD 명령
이 명령은 `#[test]`, rstest, proptest, mockall을 사용하여 Rust 코드에 대해 테스트 주도 개발(Test-Driven Development) 방법론을 강제합니다.
## 이 명령이 수행하는 작업
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
사용자: /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 모범 사례
**해야 할 일 (DO):**
- 구현 전에 먼저 테스트를 작성하세요
- 각 변경 후 테스트를 실행하세요
- 더 나은 오류 메시지를 위해 `assert!`보다 `assert_eq!`를 사용하세요
- 더 깔끔한 출력을 위해 `Result`를 반환하는 테스트에서 `?`를 사용하세요
- 구현이 아닌 동작을 테스트하세요
- 엣지 케이스(빈 값, 경계값, 오류 경로)를 포함하세요
**하지 말아야 할 일 (DON'T):**
- 테스트를 작성하기 전에 구현을 작성하지 마세요
- RED 단계를 건너뛰지 마세요
- `Result::is_err()`로 충분한 경우 `#[should_panic]`를 사용하지 마세요
- 테스트에서 `sleep()`을 사용하지 마세요 — 채널 또는 `tokio::time::pause()`를 사용하세요
- 모든 것을 모킹하지 마세요 — 가능하면 통합 테스트를 선호하세요
## 관련 명령
- `/rust-build` - 빌드 오류 수정
- `/rust-review` - 구현 후 코드 리뷰
- `verification-loop` skill - 전체 검증 루프 실행
## 관련 항목
- Skill: `skills/rust-testing/`
- Skill: `skills/rust-patterns/`필요한 도구
호버하면 설명CC
설치 + 호출 (2단계)
Claude Code CLI 기준.
- 1
SKILL.md 저장
아래 버튼으로 복사 → 다음 경로로 저장.
~/.claude/skills/everything-claude-code-rust-tdd/SKILL.md - 2
호출
Claude Code 채팅창에서 자연어로 부르면 자동 발동:
예) Rust 프로젝트에서 TDD(테스트 주도 개발) 원칙을 엄격하게 지키고
트리거가 안 잡히면 SKILL.md의
description줄에 더 구체적인 한국어 키워드를 추가해보세요.