TDD & Tidy First Skill (Rust Edition)
Kent Beck의 Test-Driven Development(TDD)와 Tidy First 원칙을 따르는 Rust 개발 가이드입니다.
언제 이 스킬을 사용하나요?
- •새로운 기능 구현 시
- •버그 수정 시
- •리팩토링 작업 시
- •코드 품질 향상 작업 시
핵심 개발 원칙
TDD 사이클: Red -> Green -> Refactor
- •Red: 실패하는 테스트를 먼저 작성
- •Green: 테스트를 통과하는 최소한의 코드 구현
- •Refactor: 테스트 통과 후 코드 개선
Rust TDD 방법론 가이드
테스트 작성 원칙
- •작은 기능 증분을 정의하는 실패 테스트부터 시작
- •행동을 설명하는 의미 있는 테스트 이름 사용 (예:
should_sum_two_positive_numbers) - •
#[test]속성과assert!,assert_eq!,assert_ne!매크로 활용 - •테스트를 통과시키기 위한 최소한의 코드만 작성
- •테스트 통과 후 리팩토링 필요성 검토
Rust 테스트 구조
rust
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn should_return_guide_message_for_valid_input() {
// Arrange
let service = AiService::new(mock_client());
let input = "오늘 프로젝트를 진행하면서...";
// Act
let result = service.provide_guide(input);
// Assert
assert!(result.is_ok());
assert!(!result.unwrap().guide_message.is_empty());
}
#[test]
fn should_return_error_for_invalid_secret_key() {
// Arrange
let validator = SecretKeyValidator::new("correct_key");
// Act
let result = validator.validate("wrong_key");
// Assert
assert!(result.is_err());
assert!(matches!(result, Err(AppError::InvalidSecretKey)));
}
}
비동기 테스트 (Tokio)
rust
#[cfg(test)]
mod tests {
use super::*;
#[tokio::test]
async fn should_call_openai_api_successfully() {
let client = AsyncOpenAI::new();
let response = client.chat().create(request).await;
assert!(response.is_ok());
}
}
버그 수정 시 TDD
버그 수정 시에는:
- •먼저 실패하는 테스트 작성 (버그 재현)
- •문제를 재현하는 가장 작은 테스트 작성
- •두 테스트 모두 통과하도록 수정
Tidy First 접근법
모든 변경을 두 가지 유형으로 분리:
1. 구조적 변경 (Structural Changes)
행동 변경 없이 코드 재배치:
- •이름 변경 (
rename) - •함수 추출 (
extract function) - •모듈 분리
- •
impl블록 재구성
2. 행동적 변경 (Behavioral Changes)
실제 기능 추가 또는 수정
핵심 규칙
- •구조적 변경과 행동적 변경을 같은 커밋에 섞지 않는다
- •둘 다 필요할 때는 항상 구조적 변경을 먼저 수행
- •구조적 변경 전후로 테스트를 실행하여 행동 변화 없음을 검증
커밋 규율
커밋은 다음 조건을 모두 만족할 때만:
- •
cargo test모든 테스트 통과 - •
cargo clippy모든 경고 해결 - •
cargo fmt포맷팅 완료 - •단일 논리 단위의 작업
- •커밋 메시지에 구조적/행동적 변경 여부 명시
작고 빈번한 커밋을 크고 드문 커밋보다 선호합니다.
Rust 코드 품질 표준
- •중복 제거:
DRY원칙, trait/generic 활용 - •의도 표현: 명확한 타입과 함수명
- •에러 처리:
Result<T, E>사용,?연산자 활용 - •소유권: 명확한 소유권 경계
- •상태 최소화: immutable by default
체크리스트
기능 구현 전
- • 실패하는 테스트 작성됨
- • 테스트 이름이 행동을 설명함
구현 중
- • 테스트 통과를 위한 최소 코드만 작성
- • 모든 테스트가 Green 상태
커밋 전
- •
cargo test통과 - •
cargo clippy경고 없음 - •
cargo fmt적용 - • 구조적/행동적 변경 분리됨
- • 커밋 메시지가 변경 유형 명시
항상 한 번에 하나의 테스트만 작성하고, 실행하고, 구조를 개선하세요. 매번 모든 테스트를 실행하세요.