TDD 이전의 개발 방식은 코드 개발 시간만큼 디버깅 시간에도 많이 투자해야했다.
TDD는 테스트를 먼저 하고 그 다음 구현을 한다. 기능을 검증하는 테스트 코드를 먼저 작성하고 테스트를 통과시키기 위해 개발을 진행한다.
테스트 코드를 작성 후 메서드 이름, 파라미터의 갯수, 타입, 반환 값, 메서드의 타입, 클래스의 이름 등을 결정하게 된다.
기능을 검증하는 테스트 작성
작성한 테스트를 통과하지 못하면 테스트를 통과할 만큼만 코드 작성
테스트를 통과한 뒤 개선할 코드가 있으면 리팩토링
리팩토링 수행 뒤 다시 테스트를 실행하여 기존 기능이 망가지지 않았는지 확인
위의 과정을 반복하여 점진적으로 기능을 완성해 나가기
TDD 사이클을 레드
-그린
-리팩터
라고 부르기도 한다.
각각 에러, 성공, 리팩토링 과정을 의미한다.
테스트 코드가 존재하면 리팩토링을 보다 과감하게 진행할 수 있다.
잘 동작하는 코드를 수정하는 것은 심리적으로 불안감을 주기 때문에 코드 수정을 꺼리게 만든다.
하지만 해당 기능이 온전히 동작한다는 것을 검증해주는 테스트가 있으면 코드 수정에 대한 심리적 불안감을 줄여 리팩토링을 통한 개선을 원활하게 할 수 있도록 도와준다.
TDD는 개발 과정에서 지속적으로 코드 정리를 하므로 코드 품질이 급격히 나빠지지 않게 막아주는 효과가 있으며 이는 향후 유지보수 비용을 낮추는데 기여한다.
또한 TDD를 사용하면 새로운 코드를 추가하거나 기존 코드를 수정하면 테스트를 돌려서 해당 코드가 올바른지 바로 확인이 가능하다.
이는 잘못된 코드가 배포되는 것을 방지한다.
기본적인 테스트 코드의 작성 규칙은 아래와 같다.
쉬운 경우에서 어려운 경우로 진행
예외적인 경우에서 정상인 경우로 진행
가장 구현하기 쉬운 경우부터 시작하면 빠르게 테스트를 통과 시킬 수 있다.
보통 수 분에서 십여 분 이내에 구현을 완료해서 테스트를 통과시킬 수 있을만큼 쉬운 것을 선택한다.
한 번에 구현하는 시간이 짧아지면 디버깅할 때에 유리하다.
작성한 코드가 많지 않고 작성 시간도 짧으면 머릿속에 코드에 대한 내용이 생생히 남아 있기 때문에 디버깅할 때 문제의 원인을 빠르게 찾을 수 있다.
다양한 예외 상황은 복잡한 if-else
블록을 동반할 때가 많다.
예외 상황을 전혀 고려하지 않은 코드에 예외 상황을 반영하기 위해서는 코드의 구조를 뒤집거나 코드 중간에 예외 상황을 처리하기 위해 조건문을 중복해서 추가하는 일이 벌어지며 이는 버그 발생 가능성을 높인다.
초반에 예외 상황을 테스트하면 예외 상황에 따른 if-else 구조가 미리 만들어지기 때문에 많은 코드를 완성한 뒤에 예외 상황을 반영할 때보다 코드 구조가 덜 바뀐다.
처음 TDD를 접할 때는 아래의 순서대로 구현해볼것
정해진 값을 리턴
값 비교를 이용해서 정해진 값을 리턴
다양한 테스트를 추가하면서 구현을 일반화
코드 중복은 대표적인 리팩토링 대상이다.
코드가 길어지면 메서드 추출과 같은 기법을 사용해서 메서드 이름으로 코드의 이름을 표현할 수 있다.
지속적인 리팩토링은 코드 가독성이 높아지며 이를 통해 개발자는 더욱 빠르게 코드를 분석할 수 있어 수정 요청이 있을 때 변경할 코드를 빠르게 찾을 수 있다.
이는 코드 변경의 어려움을 줄여주어 향후 유지보수에 도움이 된다.
일단 동작하는 코드를 만드는 능력은 물론 중요하지만 소프트웨어의 생존 시간이 길어질수록 소프트웨어를 지속적으로 개선, 즉 변경해야 하기 때문에 코드를 잘 변경할 수 있는 능력 또한 매우 중요하다.
코드를 잘 변경하려면 변경하기 쉬운 구조를 가져야 하는데 이를 위한 것이 바로 리팩토링이다.
상수를 변수로 바꾸거나 변수 이름을 변경하는 등의 작은 리팩토링은 발견하면 바로 실행한다.
반면에 메서드 추출과 같이 메서드의 구조에 영향을 주는 리팩토링은 큰 틀에서 구현 흐름이 눈에 들어오기 시작한 뒤에 진행한다.
테스트 코드의 중복 제거는 신중해야 한다.
테스트 코드의 구현 중복을 기계적으로 제거하면 자칫 테스트 메서드가 검증하고 싶은 내용을 알아보기 힘들 수 있다.
파라미터 개수는 적을수록 코드 가독성과 유지보수에 유리하므로 메서드의 파라미터 개수가 3개 이상이면 객체로 바꿔 한 개로 줄이는 것을 고려해야 한다.
코드 작성 전에 미리 테스트할 내용을 정리 후 리스트로 만들어보고, 그 중에 어떤 테스트가 구현이 쉬울지 상상해본다.
또는 어떤 테스트가 에외적인지 상상해본다.
테스트 과정에서 새로운 테스트 사례를 발견하면 그 사례를 목록에 추가해서 놓치지 않도록 해야한다.
지라(Jira) 또는 트렐로(Trello) 와 같은 업무 툴을 사용하면 해당 테스트 사례를 하위 작업으로 등록해서 테스트 통과 여부를 추적할 수 있다.
또한, 새로 발견한 테스트 사례를 실패하는 테스트로 등록 하는 것도 좋은 방법이 될 수 있다.
테스트 목록을 적었다고 해서 테스트를 한 번에 다 작성하면 안 된다.
한 번에 작성한 테스트 코드가 많으면 수정할 코드가 많을수록 리팩토링에 대한 심리적 저항 때문에 리팩토링을 마음껏 하지 못하게 되기 때문이다.