[Unit Testing] 단위 테스트 소개 (목표, 커버리지 지표)
포스팅에서 다루는 내용
본 게시글은 Unit Testing 도서를 정리하였습니다.
- 단위 테스트의 상태
- 단위 테스트의 목표
- 좋지 않은 테스트 스위트의 결과
- 테스트 스위트 커버리지 지표
- 성공적인 테스트 스위트의 속성
단위 테스트 현황
현재 기업용 어플리케이션 개발 프로젝트의 상당수는 좋은 코드 커버리지를 달성하고 있다. 제품 코드 : 테스트 코드 비율을 1:1 ~ 1:3까지 맞춘다. 따라서 우리는 이제 ‘좋은 단위 테스트를 작성하는 것은 어떤 의미인가?’를 고민해야 한다.
단위 테스트의 목표
코드를 단위 테스트하기 어렵다면 코드 개선이 반드시 필요하다는 것을 의미한다. 보통 강결합에서 저품질이 나타나 따로 테스트 하기 어렵다. 하지만 단위 테스트를 할 수 있다 해서 반드시 코드 품질이 좋은 것을 의미하지는 않는다. 낮은 결합도를 보여줄 수도 있다. 따라서 단위 테스트의 목표는 더 나은 설계뿐만 아니라 지속 가능한 성장을 가능하도록 하는 것이다.
테스트는 소프트웨어 엔트로피(무질서도)의 증가를 막는 안전망 역할을 하며, 회귀(변경 이전에 잘 되던 것이 변경 이후 안 되는 경우, =버그)에 대한 보험을 제공하는 도구이다. 테스트는 리팩토링 이후에도 기존 기능이 잘 작동하는지 확인하는 데에 도움을 주기 때문이다.
무작정 많은, 모든 단위 테스트를 작성하는 데에 집중하지 말고 아래 원칙을 지키는 것이 필요하다.
- 기반 코드를 리팩토링 할 때 테스트도 같이 리팩토링 하기
- 각 코드 변경 시에 테스트를 실행하기
- 테스트가 잘못된 경고를 발생시킬 경우 수정하기
- 기반 코드가 어떻게 동작하는지 이해하고자 할 때에는 테스틀르 읽는 데에 시간 투자하기
테스트도 역시 코드이며, 어플리케이션의 정확성을 보장하는 것을 목표로 하는 코드베이스의 일부로 다루어야 한다. 따라서 테스트 코드도 마찬가지로 버그에 취약하고 유지보수가 필요하다!
테스트 스위트 품질 측정을 위한 커버리지 지표
커버리지 지표는 테스트 스위트(특정 테스트 실행에서 실행될 일련의 테스트 스크립트 또는 절차)가 소스 코드를 얼마나 실행하는지를 백분율로 나타내는데, 테스트 스위트의 품질을 평가하는 데에 자주 사용된다. 커버리지가 낮다는 것은 문제의 징후이지만, 커버리지가 높다고 해서 테스트 스위츠의 품질이 높은 것은 아니다.
커버리지 지표에는 아래 두 가지 종류가 있다.
코드 커버리지 (테스트 커버리지)
코드 커버리지는 아래와 같이 계산된다.
식에 따르면, 코드가 작을수록 코드 커버리지 지표는 좋아지는데, 그렇게 하여도 테스트 스위트의 가치나 기반 코드베이스의 유지보수성이 변경되지 않기에 커버리지 숫자는 믿을만한 지표가 되지 못한다.
분기 커버리지
분기 커버리지는 코드 커버리지의 단점을 보완하였기에 코드 커버리지보다는 더 정확한 결과를 제공한다.
하지만 이 지표 또한 테스트 스위트의 품질을 결정할 수 없다.
- 테스트 대상 시스템의 모든 가능한 결과를 검증한다고 보장할 수 없기 때문이다.
- 커버리지 지표가 의미 있으려면 모든 측정 지표를 검증해야 한다..
- 상황에 따라 기반 코드를 일부 실행된 것만 보장한다.
- 또한 목적을 달성하지 못하거나 버그를 발견하지 못하는 검증이 없는 테스트는 언제나 코드/분기 커버리지가 100%를 나타낼 수 있다.
- 테스트 대상 코드에 대해 각각의 결과를 철저히 검증한다고 하더라도 신뢰할 수 있는 구조라거나 테스트 스위트 품질을 결정하는 데에 사용할 수 있다고 볼 수도 없다.
- 외부 라이브러리의 코드 경로를 고려할 수 있는 커버리지 지표가 없기 때문이다.
- 모든 커버리지 지표는 테스트 대상 시스템이 메소드를 호출할 때 외부 라이브러리가 통과하는 코드 경로를 고려하지 않는다.
- 더군다나 외부 라이브러리의 숨겨진 코드 경로나 커버리지 지표가 얼마나 있는지, 테스트가 얼마나 수행하는지는 알 방법이 없다.
- 따라서 해당 지표가 단위 테스트가 얼마나 좋은지, 나쁜지 판단할 수 없다.
위와 같은 이유로 특정 커버리지 숫자를 목표로 하여 단위 테스트를 작성하여서는 안된다. 하지만.. 시스템의 핵심 부분은 커버리지를 높게 두는 것이 좋다. 그러나 또 이 높은 수준을 요구 사항으로 삼는 것은 좋지 않다.ㅎㅎ
성공적인 테스트 스위트를 만드는 것들
가장 믿을만한 방법은 스위트 내 각 테스트를 하나씩 따로 평가하는 것이다. 테스트 스위트가 얼마나 좋은지 자동으로 확인할 수는 없지만 성공적인 테스트 스위트는 아래와 같은 특성을 가진다.
- 개발주기에 통합되어 있다.
- 모든 테스트는 개발 주기에 통합되어 있어야 한다. 이상적으로는 코드가 변경될 때마다 아무리 작은 것이라도 실행해야 한다.
- 코드베이스에서 가장 중요한 부분만을 대상으로 한다.
- 시스템의 가장 중요한 부분(비즈니스 로직이 있는 부분, 도메인 모델)에 노력을 기울이고 다른 부분(인프라 코드, DB나 서드파티 시스템과 같은 외부 서비스, 모든 것을 하나로 묶는 코드)은 간략하게 간접적으로 검증하는 것이 좋다.
- 최소한의 유지비로 가치를 끌어낸다.
- 가치가 유지비를 웃도는 테스트만 스위트에 유지하는 것이 중요하다.
- 그러기 위해서는 가치 있는 테스트를 식별하고 작성할 수 있어야 한다.
- 가치 높은 테스트를 식별하기 위해서는 기준틀이 필요하고 가치 있는 테스트를 작성하려면 코드 설계 기술을 알아야 한다.
- 코드베이스에 노력을 많이 기울여야 가치 있는 테스트도 만들 수 있다.