단위 테스트의 목표
•
단위 테스트의 목표는 무엇인가? → 더 나은 설계가 아닌 지속 가능한 성장을 가능하게 하는 것이다.
아래 그림은 테스트가 없는 일반 프로젝트의 성장 추이를 보여준다. 처음에는 발목을 잡을 것이 없으므로 빠르게 시작할 수 있다. 하지만 시간이 지나며 시간을 많이 소모해야 처음과 같은 속도로 진척을 낼 수 있다. 결국 개발 속도가 느려지고 진행하지 못할 수도 있다.
개발속도가 빠르게 감소하는 엔트로피 현상
우리는 테스트로 이런 모습을 뒤집을 수 있다. 테스트는 새로운 기능을 도입하거나 리팩토링한 후에도 기존 기능이 잘 작동하는지 확인하는데 도움이 된다.
한 가지 단점은, 초반에 상당한 노력이 필요하다는 것이다. 하지만 장기적으로 보면 그 비용을 메울 수 있다. 코드 베이스를 지속적으로 검증하는 테스트 없이는 소프트웨어 개발이 쉽게 확장되지 않는다.
좋은 테스트와 좋지 않은 테스트를 가르는 요인
아래 그림을 보면 잘못 작성한 테스트도 초반에 코드가 나빠지는 것을 늦출 수 있다. 즉, 테스트가 전혀 없는 상황에 비해 개발 속도가 덜 느려진다.
결국 침체 단계에 빠지는 잘못된 테스트가 포함된 성장 추이
테스트의 가치와 유지 비용을 모두 고려해야 한다. 이 때 비용 요소는 다음과 같은 활동에 필요한 시간에 따라 결정된다.
•
기반 코드를 리팩터링할 때 테스트도 리팩터링
•
각 코드 변경 시 테스트 실행
•
테스트가 잘못된 경고를 발생시킬 경우 처리
•
베이스 코드가 어떻게 동작하는지 이해하려고 할 때는, 테스트를 읽는 데 시간을 투자하기
높은 유지 보수 비용으로 인해 가치가 0에 가깝거나 0보다 작은 테스트를 만들기 쉬운데, 우리는 지속 가능한 프로젝트 성장을 위해서 고품질 테스트에만 집중해야 한다.
테스트도 결국 코드다. 다른 프로덕션 코드와 마찬가지로 버그에 취약하고 유지 보수가 필요하다.
좋은 단위 테스트와 나쁜 단위 테스트를 구별하는 방법은 4장에서 살펴보자.
테스트 스위트 품질 측정을 위한 커버리지 지표
이 절에서는 가장 널리 사용되는 두 가지 커버리지 지표(코드, 분기)를 어떻게 계산하고 어떻게 사용하는지 살펴보고 관련 문제점을 알아볼 것이다.
커버리지 지표는 테스트 스위트의 품질을 평가하는데 자주 사용되고 일반적으로 숫자가 높을 수록 더 좋다. 하지만 테스트 스위트 품질을 효과적으로 측정하는데 사용될 수는 없다.
커버리지가 너무 적을 때는 테스트가 충분치 않다는 증거이다. 그러나 반대의 경우로 100% 커버리지라고 해서 반드시 좋은 테스트 스위트라고 보장할 수는 없다.
코드 커버리지 지표에 대한 이해
가장 많이 사용되는 커버리지 지표로 코드 커버리지가 있으며, 테스트 커버리지로도 알려져 있다.
위 수식에서 보이는 것처럼 하나 이상의 테스트로 실행된 코드 라인 수와 제품 코드베이스의 전체 라인 수의 비율을 나타내는 것이 코드 커버리지이다.
예제 1.1 확인
위 예제는 커버리지 숫자에 대해 얼마나 쉽게 장난칠 수 있는지 보여준다. 단순히 코드를 더 작게 한다 한들, 테스트 스위트의 가치나 기반 코드의 유지 보수성이 변경되지 않는다.
분기 커버리지 지표에 대한 이해
또 다른 커버리지 지표는 분기 커버리지인데, 코드 커버리지의 단점을 극복하는 데 도움이 되므로 더 정확한 결과를 제공한다.
분기 커버리지 지표는 if문과 switch문과 같은 제어 구조에 중점을 둔다.
1.1 예제를 다시 보면, 메서드에 두 개의 분기가 있는데, 하나는 문자열의 길이가 5자를 넘어가는 상황에 대한 것이고, 다른 하나는 그렇지 않은 경우다.
테스트는 이 분기 중 하나에 대해서만 적용되어 있으므로(3자) 분기 커버리지 지표는 1/2 = 50%이다.
커버리지 지표에 관한 문제점
테스트 스위트의 품질을 결정하는 데 어떤 커버리지 지표도 의존할 수 없는 이유는 다음과 같다.
•
테스트 대상 시스템의 모든 가능한 결과를 검증한다고 보장할 수 없다.
•
외부 라이브러리의 코드 경로를 고려할 수 있는 커버리지 지표는 없다.
1번째 이유에 대한 설명을 알아보자. 커버리지 지표가 의미 있으려면, 모든 측정 지표를 검증해야 한다.
•
isStringLong 메서드의 다른 버전을 보여주는 예시 확인
•
검증하지 않는 테스트 코드의 예시 확인
2번째 이유에 대한 설명을 알아보자. 외부 라이브러리의 코드 경로를 고려해야 한다는 것이 아니라, 해당 지표로는 단위 테스트가 좋은지 나쁜지를 판단할 수 없다는 것을 보여준다.
•
예시 확인
특정 커버리지 숫자를 목표로 하기
커버리지 지표는 좋은 부정 지표이지만 나쁜 긍정 지표이다. 코드 커버리지를 측정하는 것은 품질 테스트 스위트로 가는 첫 걸음일 뿐이다. 이를 목표로 정해서는 안 된다.
무엇이 성공적인 테스트 스위트를 만드는가?
테스트 스위트가 얼마나 좋은지 자동으로 확인할 수는 없다. 개인 판단에 맡겨야 한다. 성공적인 테스트 스위트는 다음과 같은 특성을 가지고 있다.
•
개발 주기에 통합되어 있다.
•
코드 베이스에서 가장 중요한 부분만을 대상으로 한다.
•
최소한의 유지비로 최대의 가치를 끌어낸다.
개발 주기에 통합되어 있음
자동화된 테스트를 할 수 있는 방법은 끊임없이 테스트 하는 것 뿐이다. 모든 테스트는 개발 주기에 통합되어야 하며 이상적으로는 코드가 변경될 때마다 아무리 작은 테스트라도 실행되어야 한다.
코드 베이스에서 가장 중요한 부분만을 대상으로 함
모든 테스트가 똑같지 않은 것처럼, 코드 베이스의 모든 부분에 똑같이 주목할 필요는 없다.
대부분의 애플리케이션에서 가장 중요한 부분은 비즈니스 로직이 있는 부분이다. 비즈니스 로직 테스트가 시간 투자 대비 최고의 수익을 낼 수 있다.
다른 모든 부분은 세 가지 범주로 나눌 수 있다.
•
인프라 코드
•
DB나 서드파티 시스템과 같은 외부 서비스 및 종속성
•
모든 것을 하나로 묶는 코드
도메인 모델을 다른 애플리케이션 문제와 분리해야 단위 테스트에 대한 노력을 도메인 모델에만 집중할 수 있다. 이것은 2부에서 자세히 살펴보자.
최소 유지비로 최대 가치를 끌어냄
최소 유지비로 최대 가치를 달성하는 것은 테스트를 빌드 시스템에 통합하는 것만으로는 충분하지 않고, 도메인에 대한 높은 테스트 커버리지를 유지하는 것도 충분하지 않다.
가치가 유지비를 상회하는 테스트만 스위트에 유지하는 것이 중요하다.
•
가치 있는 테스트 식별하기
•
가치 있는 테스트 작성하기
이 책을 통해 배우는 것
이 책을 통해 테스트 스위트 내의 모든 테스트를 분석하는 데 사용할 수 있는 기준틀을 설명한다. 이 기준틀을 기초로 잡고 더 새로운 관점에서 많은 테스트를 보며 어떤 것이 프로젝트에 기여하고 어떤 것을 리팩터링해야 하거나 제거해야 하는지 알 수 있을 것이다.
이 책에서는 단위 테스트의 기초를 다지고(4장), 단위 테스트 기술과 실천을 살펴본다(4~7장, 7장 일부).
또한 다음 내용도 다룬다.
•
프로덕션 코드와 관련된 테스트 스위트를 리팩터링하기
•
단위 테스트를 다양한 스타일로 적용하기
•
통합 테스트로 시스템 전체 동작 검증하기
•
단위 테스트 안티 패턴을 식별하고 예방하기