테스트 코드 작성 순서
- 2장에서 테스트 코드를 작성한 순서는 다음과 같다.
- 쉬운 경우에서 어려운 경우로 진행
- 예외적인 경우에서 정상인 경우로 진행
- 반대로 어려운 경우를 먼저 시작하거나 정상 상황을 먼저 시작하면 구현 과정이 원활하게 진행되지 않기도 한다.
초반에 복잡한 테스트부터 시작하면 안 되는 이유
- 초반부터 다양한 조합을 검사하는 복잡한 상황을 테스트로 추가하면 해당 테스트를 통과시키기 위해 한 번에 구현해야 할 코드가 많아진다.
- 이 테스트를 통과시키려면 어떻게 해야 할까? 가장 빨리 통과시킬 수 있는 방법은 입력 값이 "abcDef12"이면 STRONG을 리턴하는 코드를 추가하는 것이다.
- 한번에 많은 코드를 만들다 보면 나도 모르게 버그를 만들고 나중에 버그를 잡기 위해 많은 시간을 허비하게 된다.
구현하기 쉬운 테스트부터 시작하기
- 구현하기 쉬운 것이 선택 기준이 된다.
- 보통 수 분내에 구현을 완료하고 통과시킬 수 있는 테스트를 선택해야 한다.
예외 상황을 먼저 테스트해야 하는 이유
- 다양한 예외 상황은 복잡한 if-else 블록을 동반할 떄가 많다. 예외 상황을 전혀 고려하지 않은 코드에 예외 상황을 반영하려면 코드의 구조를 뒤집거나 코드 중간에 예외 상황을 처리하기 위해 조건문을 중복해서 추가하는 일이 벌어진다.
- 초반예 예외 상황을 테스트하면 이런 가능성이 줄어든다.
완급 조절
- 처음 TDD로 구현할 때 어려운 것 중 하나는 한 번에 얼마만크의 코드를 작성할 것인가이다.
- TDD 연습 단계
- 정해진 값을 리턴
- 값 비교를 이용해서 정해진 값을 리턴
- 다양한 테스트를 추가하면서 구현을 일반화
- 이런 연습 과정은 아중에 만들어야 할 코드가 잘 떠오르지 않을 때 점진적으로 구현을 진행할 수 있는 밑거름이 된다.
지속적인 리팩토링
- 매번 리팩토링을 진행해야 하는 것은 아니지만 적당한 후보가 보이면 리팩토링을 진행한다.
- 지속적으로 리팩토링을 진행하면 코드 가독성이 높아진다.
- 코드 변경의 어려움을 줄여주어 향후 유지보수에 도움이 된다.
테스트 대상 코드의 리팩토링 시점
- 테스트 대상 코드에서 상수를 변수로 바꾸거나 변수 이름을 변경하는 것과 같은 작은 리팩토링은 발견하면 바로 실행한다.
- 메소드 추출과 같이 메서드의 구조에 영향을 주는 리패토링은 큰 틀에서 구현 흐름이 눈에 들어오기 시작한 뒤에 진행한다.
- 구현 초기에는 아직 구현의 전반적인 흐름을 모르기 때문에 메서드 추출과 같은 리팩토링을 진행하면 코드 구조를 잘못 잡을 가능성이 있다.
테스트 작성 순서 연습
- 먼저 테스트 클래스 이름을 정하자.
쉬운 것부터 테스트
- 테스트를 추가할 때에는 다음 두 가지를 고려애햐 한다
- 구현하기 쉬운 것부터 먼저 테스트
- 예외 상황을 먼저 테스트
- 내용을 예측할 수 있는 짧은 이름을 사용하는 것도 방법이다.
예를 추가하면서 구현을 일반화
- 1만 원을 납부하는 예를 하나 더 추가한다.
- 이제 구현을 고민할 차례다. 이 테스트를 통과시키기 위해 한 번 더 상수를 사용할까? 아니면 바로 구현을 일반화할까? 이 예는 비교적 단순하므로 바로 구현을 일반화해도 된다.
코드 정리: 중복 제거
- 리팩토링할 시간이다.
- 발생하지도 않았는데 미리 단정 지어 코드를 수정할 필요는 없다.
- 테스트 코드의 중복 제거는 고민이 필요하다.
- 테스트 코드의 구현 중복을 기계적으로 제거하면 자칫 테스트 메서드가 검증하고 싶은 내용을 알아보기 힘들 수 있다.
- 일단 중복 제거를 해보고 테스트 코드가 여전히 자신을 설명하고 있는지 확인해보자
예외 상황 처리
- 쉬운 구현을 하나 했으니 이제 예외 상황을 찾아보자
다음 테스트 선책: 다시 예외 상황
- 그다음으로 쉽거나 예외적인 것을 선택하면 된다.
- 이전 테스트가 1개월 요금 지불을 기준으로 하므로 1개월 요금 지불에 대한 예외 상황을 마무리하고 2개월 이상 요금 지불을 테스트하는 것이 좋을 것 같다.
다음 테스트를 추가하기 전에 리팩토링
- 파라미터 개수는 적을수록 코드 가독성과 유지보수에 유리하므로 메서드의 파라미터 개수가 세 개 이상이면 객체로 바꿔 한 개로 줄이는 것을 고려해야 한다.
예외 상황 테스트 진행 계속
- 상수를 이용해서 테스트를 통과시켰으니 새로운 테스트 사례를 추가해서 구현을 일반화할 차례다.
- 테스트가 실패했으니 통과시켜보자, 테스트를 통과할 만큼만 구현을 일반화해보자
코드 정리: 상수를 변수로
- 상수 1을 [리스트 3.17]과 같이 변수로 바꾸자
- 코드를 리팩토링한 뒤에는 테스트를 다시 실행해서 깨지는 테스트가 없는지 확인한다.
다음 테스트 선택: 쉬운 테스트
- 새로 추가한 테스트도 통과한다. 이제 몇 가지 사례를 더 추가해 나가면서 구현에 문제가 없다는 것을 확인할 차례다.
예외 상황 테스트 추가
코드 정리
- 코드가 복잡한 이유 중 하나는 날짜 관련 계싼 코드가 중복해서 존재하기 때문이다.
- 코드를 수정했으면 테스트를 실행해서 깨지는 테스트가 없는지 확인한다.
- 역시 코드를 수정한 뒤에는 테스트를 실행해서 문제가 없는지 확인하다.
다음 테스트: 10개월 요금을 납부하면 1년 제공
- 지금까지 했던 것처럼 먼저 할 일은 테스트 코드를 추가하는 것이다.
- 이 테스트를 통과시켜보자, 쉬운 방법은 지불한 금액이 10만 원인지 여부를 비교하는 것이다.
테스트할 목록 정리하기
- TDD를 시작할 때 테스트할 목록을 미리 정리하면 좋다.
- 어떤 테스트가 구현이 쉬울지 상상해본다. 또는 어떤 ㅔㅌ스트가 예외적인지 상상해본다.
- 시간을 조금 들여서 구현의 난이도나 구조를 검토하면 다음 테스트를 선택할 때 도움이 된다.
- 테스트 과정에서 새로운 테스트 사례를 발견하면 그 사례를 목록에 추가해서 놓치지 않도록 해야 한다.
- 처음부터 모든 사례를 정리하려면 시간도 오래 걸릴뿐더러 쉽지도 않다.
- 테스트 목록을 적었다고 해서 테스트를 한 번에 다 작성하면 안 된다.
- 다루는 범위가 작고 개발 주기도 짧으므로 개발 집중력도 높아진다.
- 범위가 큰 리팩토링은 시간이 오래 걸리므로 TDD 흐름을 깨기 쉽다. 이때는 리팩토링을 진행하지 말고 테스트를 통과시키는 데 집중한다.
- 리팩토링 범위가 크면 리팩토링에 실패할 수도 있다. 그러니 범위가 큰 리팩토링을 진행하기 전에는 코드를 커밋하는 것을 잊지 말자.
시작이 안 될 때는 단언부터 고민
- 테스트 코드를 작성하다 보면 시작이 잘 안 될 때가 있다. 이럴 땐 검증하는 코드부터 작성하기 시작하면 도움이 된다.
구현이 막히면
- 쉬운 테스트, 예외적인 테스트
- 완급조절
'책 > 테스트 주도 개발 시작하기(완)' 카테고리의 다른 글
8장 테스트 가능한 설계 (3) | 2024.07.23 |
---|---|
7장 대역 (1) | 2024.07.17 |
6장 테스트 코드의 구성 (0) | 2024.07.17 |
4장 TDD, 기능 명세, 설계 (0) | 2024.07.09 |
2장 TDD 시작 (0) | 2024.07.03 |