테스트 코드는 리팩터링이 아니더라도 새 함수, 새 기능을 만들 때 생각하지 못했던 버그를 검출할 수도 있고,
코드가 테스트 가능하게 만들기 위해서 좀 더 나은 코드로 리팩터링 할 수도 있음.
→ 좋은 테스트를 구축하는 일은 개발효율을 높여줌.
모든 테스트를 완전히 자동화하고 결과까지 스스로 검사하도록 만들어야 함.
→ 요즘 툴들은 자동으로 테스트를 진행해 줌. 우리가 예상하는 값을 코드로 명시해 두면 알아서 검사해 주고 문제가 있을 땐 문제를 찾아줌.
컴파일할 때마다 테스트도 함께 하면서 생산성이 급상승. 디버깅 시간이 크게 줄어듦.
테스트를 자주 수행하는 습관도 버그를 찾는 강력한 도구가 됨.
→ 새로운 코드를 작성할 때, 코드 리뷰를 진행할 때에도 테스트코드를 함께 작성하도록 권장해야 함. 테스트 코드가 없다면 merge를 할 수 없도록 하는 것. merge하기 전 기존 테스트코드, 새 테스트코드가 모두 통과하는지 확인할 수 있도록 CI구축을 해놓는 것도 중요.
✨테스트를 작성하기 가장 좋은 시점은 프로그래밍을 시작하기 전.
→ TDD(Test Driven Development)는 요구사항을 먼저 파악한 후, 요구사항에 맞게 사용하는 관점에서 테스트를 먼저 작성하고 그에 맞게 구현하는 방식.
켄트 벡(Kent Beck)은 테스트부터 작성하는 습관을 바탕으로 TDD를 창시.
(처음엔 통과하지 못할) 테스트를 작성 → 이 테스트를 통과하게끔 코드를 작성 → 결과 코드를 최대한 깔끔하게 리팩터링하는 과정을 짧은 주기로 반복.
'테스트-코딩-리팩터링' 과정을 한 시간에도 여러 차례 진행하기 때문에 코드를 굉장히 생산적이면서도 차분하게 작성 가능.
비즈니스 로직이 복잡해진다면 UI와 분리하여 코드를 파악하고 테스트하기 편하게 수정할 것.
✨실패할 상황에서 반드시 실패하게 만들 것.
→ 명확하게 실패할 케이스에서 exception이 던져지는지 error가 발생하는지도 꼼꼼히 테스트에서 검증해야 함.
✨자주 테스트할 것. 작성 중인 코드는 적어도 몇 분 간격으로 테스트하고, 적어도 하루에 한 번은 전체코드 테스트를 실행해봐야 함.
→ 자주 검증하는 습관을 가질 것.
뛰어난 테스트 프레임워크를 사용하면 많은 테스트도 간편하게 실행할 수 있고 실패 시 금방 확인할 수 있음.
✨완벽하게 만드느라 테스트를 수행하지 못하느니, 불완전한 테스트라도 작성하고 실행하는 것이 나음.
→ 테스트 코드가 하나도 없는 경우라도, 어차피 다 테스트코드를 작성하는 것이 불가능함을 인정하고 프로젝트에서 정말 중요한 기능을 담당하는 모듈부터 조금이라도 테스트를 작성해 보는 것이 좋음.
setup(설정) - exercise(실행) - verify(검증) 단계로 테스트를 수행.
given(조건) - when(발생) - then(결과) 이나,
arrange(준비) - act(수행) - assert(단언) 순서로 부르기도 함.
→ '어떤 조건에 어떤 데이터가 있을 때' - '어떤 코드가 발생한다면' - '어떻게 되어야 한다'
이 세 가지 조건이 한 테스트 안에 모두 담겨 있을 수도 있고, 초기 준비 작업 중 공통되는 부분을 표준 설정 루틴에 모아서 처리하기도 함.
(teardown(해체)나 cleanup(청소)라고 부르는 네 번째 단계도 있지만 명시적으로 언급하지 않을 때가 많음)
모든 일이 순조롭고 사용자도 우리 의도대로 사용하는 '꽃길(happy path)'상황만 작성하기보다는 경계조건 검사도 작성.
✨경계조건 검사. 테스트할 때 정말 중요. 범위를 벗어나는 경계 지점에서 문제가 생기면 어떤 일이 벌어지는지 확인하는 테스트도 함께 작성하면 좋음.
→ 컬렉션이 비어있을 때 어떤 일이 발생하는지 확인. 지워진 인자의 데이터가 비어있거나, 예상보다 더 많은 사이즈로 들어올 때 어떻게 코드가 수행되어야 하는지도 검증.
✨문제가 생길 수 있는 경계조건을 생각해 보고, 그 부분을 집중적으로 테스트할 것.
✨어차피 모든 버그를 잡아낼 수 없다고 생각하여 테스트를 작성하지 않으면 대다수의 버그를 잡을 수 있는 기회를 날리는 셈.
테스트 코드 기법들이 도움이 되는 것은 분명하지만 너무 빠져들 필요는 없음. '수확 체감 법칙'이 적용되어 너무 많이 작성하다 보면 오히려 의욕이 떨어져 나중에는 하나도 작성하지 않게 될 위험이 있음.
위험한 부분에 집중하는 것이 좋음. 코드에서 처리과정이 복잡한 부분을 찾을 것. 함수에서 오류가 생길만한 부분을 찾아볼 것.
테스트가 모든 버그를 잡아주지는 못할지라도 안심하고 리팩터링 할 수 있게 해주는 보호막이 됨.
리팩터링을 하며 프로그램을 더 깊이 있게 이해하게 되어 더 많은 버그를 찾게 해 줌.
항상 Test Suite를 갖추고 리팩터링을 하지만 리팩터링을 하는 동안에도 코드를 더 이해하게 되면서 계속해서 테스트를 추가하게 됨.
테스트코드는 리팩터링에 반드시 필요한 토대일 뿐만 아니라 그 자체로도 프로그래밍의 중요한 역할을 해줌.
✨버그리포트를 받았을 때, 그 버그를 드러내는 단위 테스트부터 작성할 것.