https://product.kyobobook.co.kr/detail/S000001248962
테스트 주도 개발 시작하기 | 최범균 - 교보문고
테스트 주도 개발 시작하기 | 작동하는 깔끔한 코드를 만드는 데 필요한 습관 - JUnit 5를 이용한 테스트 주도 개발 안내 - 테스트 작성과 설계를 위한 대역 - 테스트 가능한 설계 방법 안내 - 유지
product.kyobobook.co.kr
1. TDD 이전의 개발 방식과 문제점
1-1. 전통적인 개발 흐름
- 기능 설계부터 시작
- “어떤 클래스가 필요하지?”, “어떤 인터페이스를 만들까?”, “어떤 메서드를 넣지?” 같은 걸 머릿속/노트에서 한참 고민.
- 대략 구현을 떠올린 뒤 한 번에 쭉 코딩
- 머릿속에서 디자인이 어느 정도 그려지면 코드를 왕창 작성.
- 기능 테스트 & 디버깅
- 구현이 끝났다고 느끼면 실행해 보고, 안 되면 디버깅, 로그 찍고, 브레이크포인트 걸고, 수정 반복.
1-2. 이 방식의 문제점
- 코드량이 많을수록 디버깅 지옥
- 한 번에 너무 많은 코드를 작성하면,어디서 잘못됐는지 찾는 데 시간이 오래 걸림.
- 기능 단위 검증이 아니라 ‘전체 동작’만 보는 테스트
- 주로 UI나 전체 기능을 통해서만 테스트해서,세부 로직 별로 정확히 검증하기 힘듦.
- “문제가 나와야 고치는” 후행형 개발
- 문제는 항상 나중에 발견됨 → 수정 비용, 멘탈 데미지 증가 그래서 “이제는 다른 흐름이 필요하다”고 이야기하고, 그 대안으로 TDD를 소개한다.
2. TDD란? – 정의와 기본 철학
2-1. TDD의 한 줄 정의 “테스트부터 시작하는 개발 방식”
- 구현을 먼저 작성하고 나중에 테스트하는 게 아니라,
- 기능을 검증하는 테스트 코드를 먼저 작성하고,
- 그 테스트를 통과시키기 위해 **필요한 만큼만 구현**한다.
2-2. “테스트가 개발을 이끈다”
- TDD에서는 테스트가 ‘다음에 무엇을 만들지’ 결정하는 역할을 한다고 강조
- 테스트 코드가 “이제 이런 상황에서도 이렇게 동작해야 해”라고 규칙을 못 박으면,
- 우리는 그 테스트를 통과시키는 최소한의 코드만 작성.
- 이렇게 테스트가 늘어나면서, 구현도 점점 완성되어 감.
3. TDD 기본 흐름 – RED / GREEN / REFACTOR
3-1. 전형적인 TDD 사이클
- RED – 실패하는 테스트 작성
- 아직 구현이 없거나 불완전하니까, 테스트를 먼저 작성하면 당연히 실패하거나 컴파일 에러가 난다.
- GREEN – 테스트를 통과시키는 최소 구현
- 테스트를 통과시키기 위해 필요한 만큼만 코드 작성.
- “정답스럽게” 짜려고 욕심내지 말고, 일단 초록색(성공) 먼저.
- REFACTOR – 설계 개선
- 테스트가 모두 초록인 상태에서 중복/구조를 정리.
- 이름 개선, 중복 제거, 메서드 추출, 책임 분리 등.
- 리팩토링 후에는 테스트를 다시 실행해서 기존 기능이 안 깨졌는지 확인.
이 사이클을 계속 돌리면서 기능을 점진적으로 완성해 가는 것이 TDD
4. 예제: 암호 검사기
“문자열을 검사해서 암호를 약함/보통/강함으로 구분하는 기능을 TDD로 개발하기”.
4-1. 요구사항 정의
암호를 아래 세 가지 규칙으로 검사
- 길이가 8글자 이상
- 0–9 사이 숫자를 하나 이상 포함
- 대문자를 하나 이상 포함
그리고 규칙 충족 개수에 따라 등급을 나눔:
- 세 가지 규칙을 모두 충족 → “강함(strong)”
- 두 가지 규칙만 충족 → “보통(normal)”
- 한 가지 이하 충족 → “약함(weak)”
4-2. TDD 첫 스텝: 가장 쉬운 테스트부터
“첫 테스트는 가장 쉽거나 가장 예외적인 케이스로 시작하라”
- “모든 규칙을 다 만족하는 암호 → 강함” 같은 직관적인 케이스를 첫 테스트로 잡는 식.
- 테스트 클래스부터 만든다.
- 예: PasswordStrengthMeterTest
- 아직 존재하지 않는 클래스/메서드 이름을 고민하면서 바로 테스트 코드 작성
- new PasswordStrengthMeter().meter("ab12!ABCD") 같은 식으로, 아직 없는 타입/메서드를 테스트에서 먼저 호출
- 그러면 당연히 컴파일 에러 발생 →에러를 없앨 만큼만 최소한의 클래스/메서드 뼈대를 만든다.
이 시점에서는 구현이 아니라 “타입과 메서드 모양”만 잡는다는 게 포인트.
4-3. GREEN: 테스트를 통과시키는 최소 구현
첫 테스트를 만들고 나면, 이제 실패/컴파일 에러 상태를 GREEN으로 바꾸는 단계로 넘어간다.
- 예를 들어, ab12!ABCD가 강함으로 평가돼야 한다면,
- 테스트에서 assertEquals(PasswordStrength.STRONG, meter.meter("ab12!ABCD"));
- 구현에서는 아주 단순하게 강함만 반환하는 코드로 시작
이때 중요한 건
- 처음부터 모든 규칙을 구현하지 않아도 된다.
- “테스트를 통과하기 위해 필요한 최소한”만 구현하고, 나머지 요구사항은 다음 테스트들에서 조금씩 채워나간다.
4-4. 테스트 추가 & 구현 확장
첫 테스트를 통과시키면, 다음 흐름으로 반복
- 두 번째 테스트 추가
- 예: 한 규칙만 만족하는 암호는 약함이어야 한다.
- 테스트 실행 → 실패
- 기존 구현이 첫 테스트만 통과하게 억지로 짜놨다면, 다른 케이스에서 당연히 깨짐.
- 구현을 확장
- 이제는 “규칙 몇 개를 만족하는지 세는 로직”을 조금 더 일반화.
- GREEN 상태가 되면, 필요 시 리팩토링:
- 규칙 검사 메서드 분리 (길이 검사, 숫자 포함 여부, 대문자 포함 여부 등)
- 중복 제거, 이름 개선, 조건문 단순화 등.
이 과정을 여러 번 반복하면서, 암호 검사기가 점점 “진짜 요구사항을 만족하는 함수”로 완성된다.
4-5. 예외/에러 케이스도 테스트부터
“에러 케이스도 TDD의 일부로 먼저 다룬다”
- null이 들어왔을 때 어떻게 할지?
- 너무 짧은 문자열일 때?
- 숫자/대문자가 전혀 없는 경우?
이런 케이스들을 테스트로 먼저 명시해 두면 구현에서 그 상황을 처리할지/예외를 던질지 명확해지고, 나중에 코드가 복잡해져도 테스트가 안전망 역할을 해줌.
5. 강조하는 TDD 실천 원칙들
2장 끝부분과 각종 요약 글에서 반복해서 등장하는 핵심 원칙들을 정리해 보면
5-1. 테스트부터 작성하라
- “Test Case 먼저”
- 프로덕션 코드(구현 코드)는 테스트가 요구하는 만큼만 작성.
- 구현 아이디어가 떠올라도 테스트로 먼저 눌러 담고 시작하는 패턴을 몸에 익히는 게 중요.
5-2. 쉬운 케이스부터
- 첫 테스트는 가장 단순하거나 대표적인 케이스로.
- 너무 많은 경우를 한 번에 커버하려고 하지 않는다.
- 이렇게 해야 한 스텝에서 변경하는 코드량이 적어져서 디버깅이 쉬움.
5-3. 한 번에 개발하는 양을 줄여라
- “한 번에 큰 기능을 완성하겠다”는 생각 대신, 테스트 하나를 만족시키는 최소 단위 변경”에 집중.
- 작은 스텝일수록:
- 실패 지점이 명확해지고,
- 회귀 버그를 찾기가 쉬워지고,
- 설계 개선도 반복적으로 할 수 있음.
5-4. 에러 케이스를 충분히 고려하라
- 성공 케이스뿐 아니라 실패/경계 상황을 테스트로 명시.
- 암호 검사기처럼 규칙이 있는 기능에서는 특히
- 경계값(길이 7 vs 8),
- 한 규칙만 충족 / 두 규칙만 충족 같은 경우를 테스트로 꼭 넣자.
5-5. 테스트 코드도 코드다 (가독성 중요)
- 테스트도 결국 유지보수 대상이기 때문에 중복 제거, 의미 있는 메서드 이름, 명확한Arrange/Act/Assert 구조를 갖추는 게 좋다.
- “테스트가 복잡해서 이해가 안 되면, 그 테스트로 보호받는 느낌이 안 난다”는 메시지도 담겨 있다.
5-6. src/test/java에서 먼저 작업하고, 나중에 main으로 옮기기
- 처음에는 테스트 소스 폴더에서만 클래스/메서드를 만들고, 나중에 충분히 안정화되면 main으로 옮긴다
- 이렇게 하면 “미완성 프로덕션 코드가 빌드/배포에 섞이는 것”을 피할 수 있고, 실험적인 설계를 테스트 영역에서 마음껏 해볼 수 있음.
핵심 정리
- 빠른 피드백
- 코드를 조금 바꾸고 바로 테스트를 돌려 확인 →잘못된 코드가 배포 이전에 바로 걸러짐.
- 회귀 버그 방지
- 새로운 기능을 추가할 때마다 이전 테스트들이 안전망 역할.
- 설계 개선 유도
- 테스트하기 어렵게 설계된 코드는 자연스럽게 리팩토링하게 됨.
- 규칙 검사 로직 분리, 책임 나누기 같은 것들이 자연스럽게 따라옴.
- 심리적 안정감
- “내가 한 수정이 다른 부분을 깨뜨릴까?” 하는 불안이 줄어듦.
TDD 이전 방식의 문제 → 한 번에 많은 코드 작성, 늦은 피드백, 디버깅 지옥
- TDD 정의 → 테스트 먼저, 구현은 “테스트를 통과할 정도로만”, 그 뒤 리팩토링
- RED – GREEN – REFACTOR → 실패하는 테스트 → 최소 구현으로 통과 → 설계 개선
- 암호 검사기 예제 → 규칙 3개(길이·숫자·대문자) + 강/보통/약 구분을 TDD로 점진 구현
- 실천 원칙
- 테스트 케이스부터
- 쉬운 케이스부터
- 작은 단위로 개발
- 에러/경계 케이스까지 테스트
- 테스트 코드도 가독성/중복 제거 신경
'외부활동 > 우아한테크코스 [프리코스]' 카테고리의 다른 글
| 테스트주도 개발 시작하기 - 챕터 4. TDD, 기능명세, 설계 (0) | 2025.11.05 |
|---|---|
| 테스트주도 개발 시작하기 - 챕터 3. 테스트 코드 작성 순서 (0) | 2025.11.04 |
| [우아한테크코스 8기] 프리코스 3주차 회고 (0) | 2025.11.04 |
| 도메인의 성장과 Service 계층의 관계 (0) | 2025.11.02 |
| 책임과 무한 리팩토링(정보 전문가 vs 단일책임원칙) (0) | 2025.10.31 |