•
1장에서 다루는 내용
◦
단위 테스트의 상태
◦
단위 테스트의 목표
◦
좋지 않은 테스트 스위트의 결과
◦
테스트 스위트 커버리지 지표
◦
성공적인 테스트 스위트의 속성
•
단위 테스트는 단순히 테스트를 작성하는 테스트 프레임워크, 모킹 라이브러리를 공부하며 기술을 익히는 것을 포함하는 아주 큰 범주의 개념이다.
•
단위 테스트를 작성할 때는 들이는 노력을 가능한 줄이고 이득을 최대화하는 것을 목표로 해야 한다.
◦
이러한 프로젝트들은 무난하게 성장하고 유지보수가 많이 필요하지 않으며 변화하는 요구사항에 신속히 대응할 수 있다.
◦
그렇지 않은 경우, 노력을 많이 들이고 단위 테스트를 매우 많이 작성하더라도 많은 버그와 유지비로 프로젝트 진행이 느려지게 된다.
•
이런 차이는 단위 테스트를 어떻게 하는가에서 온다.
◦
이 책에서 다루는 내용은 어떤 단위 테스트 기술이 좋은지를 구별하는 데 도움을 준다.
▪
테스트에 대한 비용 편익 분석 방법을 배우고 특정 상황 별 적절한 테스트 기술을 학습한다.
▪
공통적인 안티 패턴을 피하는 방법도 배운다.
•
이 장에서는 단위 테스트의 현황을 살펴보고 테스트 작성과 유지보수의 목표를 설명하며 테스트 스위트를 잘 작성하기 위한 방법을 소개한다.
1. 단위 테스트 현황
•
대부분의 프로그래머는 단위 테스트를 실천하고 그 중요성을 알고 있다. 단위 테스트를 적용해야 하는가는 더이상 논쟁거리가 되지 못한다.
•
논쟁거리는 좋은 단위 테스트를 작성하는 것은 어떤 의미인가로 바뀌었다.
2. 단위 테스트의 목표
•
단위 테스트를 작성하면 제품 코드 또한 더 나은 설계로 이어진다.
◦
이는 단위 테스트의 주목표가 아니다. 더 나은 설계는 단지 좋은 사이드 이펙트일 뿐이다.
◦
코드의 단위 테스트를 작성하기 어렵다면 코드 개선이 반드시 필요하다는 것을 의미한다.
▪
보통은 코드 간의 결합도가 높을 때, 개선이 필요한 코드임을 의미하는데, 코드가 서로 충분히 분리되지 않아서 테스트하기가 어렵기 때문이다.
•
단위 테스트의 목표는 소프트웨어 프로젝트의 지속 가능한 성장을 가능하게 하는 것이다.
◦
지속 가능하다는 것이 핵심이다. 이는 프로젝트가 시간이 지나도 생산성을 잃지 않는다는 것을 의미한다.
▪
생산성이 빠르게 저하되는 현상을 소프트웨어 엔트로피라고도 한다. 코드를 작성하면 무조건 엔트로피는 증가한다. 지속적인 정리와 리팩토링없이 방치한다면 엔트로피는 점점 더 복잡해지고 무질서해진다.
▪
테스트로 이를 막을 수 있다. 새로운 기능을 도입하거나 새로운 요구 사항에 더 잘 맞게 리팩토링한 후에도 기존 기능이 잘 작동하는지 확인하는 데 도움이 된다.
◦
소스 코드를 지속적으로 검증하는 테스트없이는 소프트웨어는 쉽게 확장되지 않는다.
•
소프트웨어는 지속성과 확장성이 핵심이며 이는 장기적으로 생산성을 유지하기 위한 요소들이다.
1. 좋은 테스트와 좋지 않은 테스트를 가르는 요인
•
좋은 테스트는 프로젝트의 생산성을 유지시켜준다. 나쁜 테스트는 오히려 악화시킨다.
•
테스트의 가치와 유지 비용을 모두 고려해야 한다.
◦
비용이란 다양한 활동에 소모되는 시간에 따라 결정된다.
▪
테스트의 기반이 되는 코드를 리팩토링할 때, 테스트 코드도 리팩토링해야 한다.
▪
코드가 변경되는 경우, 테스트를 실행해야 한다.
▪
테스트가 실패하거나 의도대로 동작하지 않는 경우 수정해야 한다.
▪
테스트 코드는 기반 코드를 이해할 수 있게 도와준다.
•
프로젝트의 생산성을 유지하기 위해서는 고품질 테스트에 집중해야 한다.
제품 코드 vs 테스트 코드
•
제품 코드와 테스트 코드가 별개로 취급되는 경향 때문에 테스트 코드는 우리의 시스템과 독립되어있다고 생각한다.
•
테스트 코드도 역시 코드다. 특정 문제를 해결하는 것을 목표로 작성된 코드로 시스템에선 애플리케이션의 정확성을 보장하는 것을 목표로하는 소스 코드의 일부로 보아야 한다.
•
다른 코드와 마찬가지로 단위 테스트도 버그에 취약하고 유지보수가 필요하다.
3. 테스트 스위트 품질 측정을 위한 커버리지 지표
•
현재 테스트의 품질 측정을 위해 널리 사용되는 커버리지 지표는 코드 커버리지와 분기 커버리지다.
◦
일반적으로 커버지리 수치가 높을수록 더 좋다는 인식이 만연하다.
•
생산성을 위한 피드백으로 사용될 순 있어도 스위트 품질을 나타내는 지표로 활용하기엔 어렵다.
◦
이는 괜찮은 부정 지표이면서 좋지 않은 긍정 지표다.
◦
커버리지가 낮다면 테스트가 충분치 않다는 좋은 증거지만 커버리지가 높다고 해서 테스트가 좋다는 증거로 활용될 수는 없다.
1. 코드 커버리지 지표에 대한 이해
•
코드 커버리지는 제품 코드 라인 수 / 전체 라인 수로 표현된다.
◦
단순히 조건문의 내용을 메소드로 추출하기만 해도 해당 내용을 테스트하지 않지만 해당 테스트 코드의 코드 커버리지는 향상된다.
2. 분기 커버리지 지표에 대한 이해
•
분기로 인해 발생하는 경로들을 얼마나 테스트했는가에 대한 지표이다.
◦
분기 커버리지는 코드 커버리지보다 더 정확한 결과를 제공한다.
◦
분기 커버리지 지표는 코드 라인 수를 사용하는 대신 if, switch 문과 같은 제어 구조에 중점을 둔다.
•
분기 커버리지는 테스트 스위트에서 통과하는 테스트의 제어 구조의 수를 전체 분기 수로 나눈 것이다.
3. 커버리지 지표에 관한 문제점
•
아쉽게도 어떤 커버리지 지표도 사용할 수 없는 이유는 다음과 같다.
◦
테스트 대상 시스템의 모든 경로를 검증한다고 보장할 수 없다.
◦
외부 의존성의 경로를 고려할 수 있는 커버리지 지표는 없다.
4. 특정 커버리지 숫자를 목표로 하기
•
커버리지 지표를 보는 가장 좋은 방법은 지표에 의미 부여를 하지 않으면서도 목표로 두는 것이다.
•
커버리지는 좋은 부정 지표이지만 좋지 않은 긍정 지표다. 커버리지 숫자를 낮게 두지만 말자.
4. 무엇이 성공적인 테스트 스위트를 만드는가?
•
좋은 테스트 스위트의 요소는 다음과 같다.
1. 개발 주기에 통합되어 있다.
•
모든 테스트는 개발 주기에 포함되어 있어야 한다. 이상적으로는 코드가 변경될 때마다 테스트가 실행되는 것이다.
2. 코드베이스에서 가장 중요한 부분만을 대상으로 한다.
•
시스템의 가장 중요한 부분에 노력을 기울이고 다른 부분은 간략, 간접적으로 검증하는 것이 좋다.
•
보통 가장 중요한 부분은 비즈니스 로직(도메인 모델)이 있는 부분이다. 비즈니스 로직의 테스트 코드가 시간 투자 대비 최고의 이득을 낼 수 있다.
•
다른 부분들은 세 가지 범주로 나눌 수 있다.
◦
인프라 코드
◦
데이터베이스나 서드파티 시스템같은 외부 서비스 및 종속성
◦
모든 것을 하나로 묶는 코드
•
이 지침에서 의미하는 말은 도메인 모델을 중요하지 않은 부분(외부 종속성)과 분리하라는 것이다.
3. 최소한의 유지비로 최대의 가치를 끌어낸다.
•
단위 테스트에서 가장 어려운 것은 최소 유지비로 최대 가치를 달성하는 것이다.
⇒ 이는 이 책에서 주장하는 핵심이다.
•
가치가 유지비를 상회하는 테스트만 스위트에 유지하는 것이 중요하다.
◦
마지막 속성은 다음과 같은 두 가지로 나눠질 수 있다.
▪
가치 있는 테스트 식별하기, 가치가 낮은 테스트 식별하기
▪
가치 있는 테스트 작성하기
5. 이 책을 통해 배우는 것
•
이 책을 통해 모든 테스트를 분석하는 데 사용할 수 있는 기준을 배워갈 수 있을 것이다.
•
새로운 관점에서 어떤 것이 가치있고 어떤 것을 리팩토링하거나 제거해야 하는 지 알 수 있을 것이다.
•
다음 방법들도 배워갈 수 있다.
◦
제품 코드와 관련 테스트 스위트를 리팩토링하는 방법
◦
단위 테스트를 다양한 스타일로 적용하는 방법
◦
통합 테스트로 시스템 전체 동작 검증하기
◦
단위 테스트 안티 패턴을 식별하고 예방하기
•
4장에서 기초를 다진 후, 4~6장 그리고 7장 일부에서 기존 단위 테스트 기술과 실천을 살펴 본다.
•
이 책은 자동화된 테스트의 전체 주제를 다루기 때문에 단위 테스트 뿐만 아니라 E2E, 통합 테스트에 대해서도 알 수 있다.
요약
•
단위 테스트의 목표
◦
코드를 변경, 확장할 때마다 생산성이 낮아진다.
▪
지속적인 리팩토링과 같은 적절한 관리가 없으면 생산성은 저하된다.
▪
테스트가 이를 막아줄 수 있다. 또한 우리에게 신뢰성을 제공한다.
◦
좋은 단위 테스트를 작성하는 것이 중요하다. 잘못된 테스트를 가진 프로젝트는 생산성이 낮다.
◦
단위 테스트의 목표는 생산성을 유지시키는 것이다.
◦
모든 코드에 테스트를 작성할 필요는 없다. 존재할 가치가 있는 테스트만 남겨두어라.
•
커버리지 지표
◦
커버리지 지표는 좋은 부정 지표지만 나쁜 긍정 지표다. 낮지 않게만 유지하라.
◦
분기 커버리지로 코드 커버리지를 어느정도 보완할 수 있지만 테스트 스위트의 품질을 확인할 순 없다. 여전히 모든 경로를 확인하지 않으며 외부 의존성의 경로도 다루지 않는다.
◦
특정 커버리지 숫자를 목표로 삼는다면 이는 부적절한 행위다. 시스템의 비즈니스 로직에 커버리지를 높게 갖는 것은 좋지만 이 높은 수치를 목표로 삼는 것은 부적절한 행위라는 것이다.
•
성공적인 테스트 스위트는 다음과 같은 특성을 갖는다.
◦
개발 주기에 포함되어 있다.
◦
코드베이스 중 가장 중요한 부분만을 대상으로 한다.
◦
최소한의 유지비로 최대의 가치를 끌어낸다.
•
단위 테스트의 목표인 생산성의 유지를 달성하기 위한 유일한 방법은 다음과 같다.
◦
좋은 테스트와 좋지 않은 테스트를 식별한다.
◦
테스트를 리팩토링해서 가치를 끌어올린다.