테스트 주도 개발(TDD)의 적용
코드의 우아함을 신경쓰다보면, 코드 한줄을 짜더라도 이게 잘 구조화된 코드인가 하고 한참을 고민하게 되는데, 이게 좋은 방식인가?
그렇다고 아무렇게나 막 짜니, 코드가 지저분해지고 리팩토링하긴 무서워진다.
그래서 TDD를 학습했다.
후기
TDD 적용 방법
- 먼저, 요구사항을 제대로 이해하자.
- TDD로 일단 돌아가게 만들고, 중복을 제거하자.
- 삼각측량 기법을 적극 활용하자.
- 모든 중복을 제거하기 전까진 테스트 코드를 통과한 것으로 치지 말자.
리팩토링을 수행하지 않으면, 단편적인 기능 구현의 연속만 하게되고, 결과적으로는 유지보수하기 어려운 '단순하고 파편화된' 코드 덩어리가 만들어진다.
탑다운/바텀업 둘중 하나가 정답은 아니다.
막힐때마다 TDD도 해보고, OOD도 해보고 번갈아가며 접근해야 한다.
한가지 방식에 얽메이지 말기.
TDD-Sample
GitHub - GoGradually/TDD-Sample: Kent Beck의 TDD를 예제를 따라해보며 학습하고 회고하는 프로젝트
Kent Beck의 TDD를 예제를 따라해보며 학습하고 회고하는 프로젝트. Contribute to GoGradually/TDD-Sample development by creating an account on GitHub.
github.com
켄트 백의 TDD 예제를 직접 따라해보며, TDD에 대한 나만의 관점을 만들기 위한 프로젝트
TDD의 방법
- 필요한 Use Case를 나열한다. -> 테스트해야 하는 유스 케이스 문서(체크리스트)를 작성한다.
- 테스트 코드를 작성한다
- 테스트 코드가 실패하도록 한다. -> 테스트의 컴파일 오류를 제거한다.
- 테스트 코드가 성공하도록 한다. -> 삼각 측량 기법을 적용하라.
- 소스 코드의 중복을 제거한다. -> 소스 코드를 리팩토링한다.
- 이를 모든 유스 케이스의 시나리오가 완성될 때까지 반복한다.
- 만약 작성 도중 새로운 시나리오가 등장하면, 유스 케이스 문서에 추가해둔다.
TDD가 추구하는 것
코드를 실제로 작성하며 설계를 개선해라.
설계를 테스트 코드로 표현하는 방식을 익혀라.
각 테스트가 무엇을 사전조건으로 갖고, 무엇을 사후조건으로 갖는지 정의하라.
일단은 만들고, 중복은 나중에 제거하라.
중복을 보는 눈을 길러라.
모든 중복을 제거하기 전까진 테스트 코드를 통과한 것으로 치지 마라.
TDD의 핵심은 문제를 잘게 쪼개는 능력이다.
한꺼번에 일을 진행하지 않고, 조금씩 단계를 쪼개는 능력으로 막히는 문제를 구체화하며 해결해야 한다.
잘게 쪼갤 수 있게 만들어주는 중간 과정의 도구를 익혀라.
"왜"라는 질문으로 문제의 크기를 키우고, "어떻게" 라는 질문으로 문제의 크기를 줄여라.
메타포(은유)로 숨겨진 도메인 엔티티를 파악해라.
언제나 개발과 유지보수를 위한 "최선의 보폭"이 제일 중요하다.
TDD도 결국은 생산성을 위한 도구이다.
정해진 올바른 보폭이라는 건 존재하지 않는다.
테스트 코드를 관리하라.
필요없는 테스트는 제거하라.
불필요한 요구사항이 여전히 남아있는 것처럼 보일 수 있다.
화이트박스 테스트를 멀리하고, 블랙박스 테스트를 지향하라.
구현이 요구사항에 의존하게 만들어라. 요구사항이 구현에 의존하게 만들지 마라.
(ArgumentCaptor 사용 시, 구현에 의존하는 테스트가 되진 않았는지 주의할 것)
개인 작업 시에는 테스트를 깨진 상태로 그만두고, 팀 작업 시에는 테스트를 통과하는 상태로 그만둬라.
삼각 측량
- 성공 테스트 케이스와 실패 테스트 케이스를 모두 작성하라.
- 테스트 케이스는 2개 이상의 일반화 검증을 수행하라.
- 테스트 케이스는 2개 이상의 경계값 검증을 수행하라.장점
- precondition과 postcondition을 테스트 코드를 작성하며 그대로 설계할 수 있다.
- OOD의 메소드 책임 부여 과정을 인터랙션 다이어그램이 아닌 테스트 코드로 표현할 수 있다.
- 잘 모르는 문법에 대해서, 빠르게 테스트 해보고 구현을 가능하게 한다.
단점
- 모든 묘사가 글자로 표현이 되니, 시각화보단 실제 구현에 유리하다.
- 브레인스토밍에는 확실히 불리할 듯
- 전체적인 큰 그림을 그리지 않기에, 연쇄적 롤백이 발생할 가능성이 있다.
- 소스 코드만 보고, 중복을 파악하고, 설계를 개선하는 과정이 난이도가 좀 있다.
- 중복을 개선하기 위한 테스트 코드를 추가로 작성한다.
- 테스트 코드가 설계를 담을 수 있도록
타협점
UP의 OOA-OOD와 XP의 TDD는 둘중 하나가 정답이 아니라, 가장 생산성이 높은 방식을 선택하는 기준이 중요할 듯
- UP에서 그리는 다이어그램과 XP에서 수행하는 TDD는 둘 모두 장단점이 있다.
- TDD는 테스트 코드를 중심으로 나아가고, UP의 OOD는 문서화를 중심으로 나아간다.
- 하지만, 문서화와 테스트 코드 둘 다 중요하다고 생각하는 내 입장에선, 필요에 따라 적절한 도구를 선택하는게 좋아보인다.
- OOA의 Use Case/Domain Model 작성
- 동사 추출/명사 추출법 등으로 계약/메소드 추출
- 막힌다는 느낌이 들면 TDD로 전환해서 문제를 잘게 쪼개는 것이 좋을듯.
XP도 "CRC 카드"와 같은 작업을 통해 OOA의 도메인 모델 작성과 유사한 과정을 거치긴 한다.
처음 문법/API를 사용하게 된다면, TDD를 적극 활용하자.
- 이때는 보통 아키텍처보다 문법의 옳고 그름이 중요하게 되니, TDD가 더 유리해진다.
한계
- 테스트 코드는 다음 것들을 대체하진 못한다.
- 성능 테스트
- 스트레스 테스트
- 사용성 테스트