- 좋은 단위 테스트 스위트의 특성
- 개발 주기에 통합돼 있다.
- 코드베이스의 가장 중요한 부분만을 대상으로 한다.
- 최소한의 유지비로 최대 가치를 끌어낸다.
- 가치있는 테스트를 작성하려면 가치있는 테스트를 식별할 수 있어야 한다.
좋은 단위 테스트의 4대 요소 자세히 살펴보기#
첫 번째 요소: 회귀 방지#
- 회귀: 코드를 수정한 후 기능이 의도한 대로 작동하지 않는 경우
- 회귀 방지 지표에 대한 테스트 점수가 얼마나 잘 나오는지 평가하려면 다음 사항을 고려해야 한다.
- 테스트 중에 실행되는 코드의 양: 테스트 중에 실행되는 코드 양이 많을수록 테스트에서 회귀를 확인할 가능성이 높다.
- 코드 복잡도: 단순한 코드는 테스트를 할 가치가 없다.
- 코드의 도메인 유사성: 복잡한 비즈니스 로직을 나타내는 코드가 보일러 플레이트 코드보다 훨씬 더 중요하다.
두 번째 요소: 리팩터링 내성#
- 테스트를 실패로 바꾸지 않고 기본 애플리케이션 코드를 리팩터링 할 수 있는지에 대한 척도다.
- 거짓 양성의 문제점
- 테스트가 타당한 이유 없이 실패하면, 리팩터링에 대한 능력과 의지를 방해한다.
- 거짓 양성이 빈번하면 테스트 스위트에 대한 신뢰가 떨어지며, 더 이상 믿을 만한 안전망으로 인식하지 않는다.
무엇이 거짓 양성의 원인인가?#
- 테스트와 SUT의 구현 세부 사항이 많이 결합할수록 허위 경보가 더 많이 생긴다.
- 거짓 양성이 생길 가능성을 줄이는 방법은 해당 구현 세부 사항에 테스트를 분리하는 것뿐이다.
- 테스트를 구성하기에 가장 좋은 방법은 문제 영역에 대해 이야기하는 것이다.
- SUT의 구현 세부 사항과 결합된 테스트는 리팩터링 내성이 없다.
구현 세부 사항 대신 최종 결과를 목표로 하기#
- 테스트를 깨지지 않게 하고 리팩터링 내성을 높이는 방법은 SUT의 구현 세부 사항과 테스트 간의 결합도를 낮추는 것 뿐이다.
첫 번째 특성과 두 번째 특성 간의 본질적인 관계#
- 회귀 방지와 리팩터링 내성은 테스트 스위트 정확도에 기여한다.
- 이 두 가지 특성은 시간이 흐르면서 프로젝트에 영향을 다르게 미치는 경향이 있다.
- 프로젝트가 시작된 직후에는 회귀 방귀 방지를 훌륭히 갖추는 것이 중요한 데 반해, 리팩터링 내성은 바로 필요하지 않다.
테스트 정확도 극대화#

- 회귀 방지와 리팩터링 내성은 테스트 스위트의 정확도를 극대화하는 것을 목표로 한다.
- 테스트가 버그 있음을 얼마나 잘 나타내는가(거짓 음성, 회귀 방지 영역)
- 테스트가 버그 없음을 얼마나 잘 나타내는가(거짓 양성,리팩터링 내성 영역)
거짓 양성과 거짓 음성의 중요성: 역학 관계#
- 프로젝트 초기에는 리팩터링이 바로 중요하지 않기 때문에 거짓 양성이 거짓 음성만큼 중요하지 않다.
- 시간이 흐를수록 코드베이스는 복잡해지고 체계적이지 않게되면서, 리팩터링을 해야한다.
- 리팩터링이 필요해짐에 따라 리팩터링 내성도 점점 더 중요해진다.
세 번째 요소와 네 번째 요소: 빠른 피드백과 유지 보수성#
- 빠른 피드백: 테스트가 빠르게 실행되면 코드에 결함이 생기자마자 버그에 대해 경고하기 시작할 정도로 피드백 루프를 대폭 줄여서, 버그를 수정하는 비용을 거의 0까지 줄일 수 있다.
- 유지 보수성: 유지 보수성 지표는 유지비를 평가한다. 이 지표는 다음 두 가지 주요 요소로 구성된다.
- 테스트가 얼마나 이해하기 어려운가: 테스트의 크기와 관련이 있다. 테스트는 코드 라인이 적을수록 더 읽기 쉽다.
- 테스트가 얼마나 실행하기 어려운가: 테스트가 프로세스 외부 종속성으로 작동하면, 데이터베이스 서버를 재부팅하고 네트워크 연결 문제를 해결하는 등의 의존성을 상시 운영하는 데 시간을 들여야 한다.
이상적인 테스트를 찾아서#
- 좋은 단위 테스트의 4대 특성
- 이 네 가지 특성을 곱하면 테스트의 가치가 결정된다.
가치 추정치 = [0..1] * [0..1] * [0..1] * [0..1]
- 테스트 코드를 포함흔 모든 코드는 책임이다. 최소 필수값에 대해 상당히 높은 임계칠르 설정하고 이 임계치를 충족하는 테스트만 테스트 스위트에 남겨라.
- 소수의 매우 가치있는 테스트는 다수의 평범한 테스트보다 프로젝트가 계속 성장하는 데 훨씬 더 효과적이다.
이상적인 테스트를 만들 수 있는가?#
- 회귀 방지, 리팩터링 내성, 빠른 피드백은 상호 배타적이기 때문에 이상적인 테스트를 만드는 것은 불가능하다.
- 세 가지 특성 모두 최대로 하는것은 불가능하다. 셋 중 하나를 희생해야 나머지 둘을 최대로 할 수 있다.
극단적인 사례 1: 엔드 투 엔드 테스트#
- 많은 코드를 테스트하믈 회귀 방지를 훌륭히 해낸다.
- 거짓 양성에 면역이 돼 리팩터링 내성도 우수하다.
- 리팩터링은 식별할 수 있는 동작을 변경하지 않으므로 엔드 투 엔드 테스트에 영향을 미치지 않는다.
- 속도가 느리다. 엔드 투 엔드 테스트에만 의존하는 모든 시스템은 피드백을 빨리 받기가 어려울 것이다.
극단적인 사례 2: 간단한 테스트#
- getter, setter 같은 간단한 테스트는 실수할 여지가 많지 않기 때문에 회귀를 나타내지 않을 것이다.
- 이러한 테스트는 항상 통과하거나 검증이 무의미하기 떄문에 어떤 것도 테스트한다고 할 수 없다.
극단적인 사례 3: 깨지기 쉬운 테스트#
- 깨지기 쉬운 테스트: 실행이 빠르고 회귀를 잡을 가능성이 높지만 거짓 양성이 많은 테스트
- 테스트가 SUT의 내부 구현 세부 사항에 결합되는 경우다.

이상적인 테스트를 찾아서: 결론#
- 좋은 단위 테스트의 세 가지 특성은 상호 배타적이라서, 두 가지를 극대화하는 테스트를 만들기는 매우 쉽지만, 나머지 특성 한 가지를 희생해야만 가능하다.
- 네 번째 특성인 유지 보수성은 엔드 투 엔드 테스트를 제외하고 처음 세가지 특성과 상관관계가 없다.
- 엔드 투 엔드 테스트는 관련된 모든 의존성을 설정해야 하므로 일반적으로 크기가 더 크다.
- 엔드 투 엔드 테스트만 쓰거나 테스트가 상당히 빠르지 않은 한, 리팩터링 내성을 최대한 많이 갖는 것을 목표로 해야 한다.
- 따라서 회귀 방지와 빠른 피드백 사이의 선택으로 절충이 귀결된다.
- 리팩터링 내성은 조금만 인정할 수는 없어서 완전히 인정하거나 포기해야한다. 반면에 회귀 방지와 빠른 피드백에 대한 지표는 조절이 가능하다.

대중적인 테스트 자동화 개념 살펴보기#
테스트 피라미드 분해#
- 테스트 피라미드: 테스트 스위트에서 테스트 유형 간의 일정한 비율을 일컫는 개념
- 단위 테스트
- 통합 테스트
- 엔드 투 엔드 테스트

- 어느 계층도 리팩터링 내성을 포기하지 않는다.
- 일반적으로 테스트 수는 피라미드 형태를 유지한다.
- 엔드 투 엔드 테스트는 빠른 피드백 지표에서 낮은 점수를 받고, 유지 보수성이 큰 편이다. 따라서, 가장 중요한 기능에 적용할 떄와 단위 테스트나 통합 테스트와 동일한 수준으로 보호할 때만 사용한다.
- 테스트 피라미드 예외
- 단순 CRUD 작업이라면, 단위 테스트와 통합 테스트 수가 같고 엔드 투 엔드 테스트가 없는 직사각형처럼 보일 것이다.
- 단위 테스트가 간단한 테스트 수준까지 내려간다.
- 통합 테스트는 데이터베이스와 같이 다른 하위 시스템과 통합돼 잘 작동하는지 확인할 수 있다.
- 프로젝트 외부 의존성(예: 데이터베이스) 하나만 연결하는 API인 경우, 엔드 투 엔드 테스트를 더 많이 두는 것이 적합하다.
- 사용자 인터페이스가 없으므로 엔드 투 엔드 테스트가 상당히 빠르게 실행된다.
- 단일 외부 의존성으로만 작동하기 떄문에 유지비도 크지 않다.
블랙박스 테스트와 화이트 박스 테스트 간의 선택#
- 블랙박스 테스트: 시스템의 내부 구조를 몰라도 시스템의 기능을 검사할 수 있는 소프트웨어 테스트 방법
- 화이트박스 테스트: 애플리케이션 내부 작업을 검증하는 테스트 방식
- 리팩터링 내성은 타협할 수 없다. 블랙박스 테스트를 기본으로 선택하라.
- 테스트 분석할 때는 화이트 박스 방법을 사용할 수 있다. 코드 커버리지 도구를 사용해서 어떤 코드 분기를 실행하지 않았는지 확인한 다음 코드 내부에 대해 전혀 모르는 것처럼 테스트하라.
comments powered by