회귀는 소프트웨어 버그이다. 코드 수정 후 기능이 의도한 대로 작동하지 않는 경우를 말한다.
일반적으로 실행되는 코드가 많을수록 회귀가 나타날 가능성이 높다.
코드의 양뿐만이 아니라 복잡성과 도메인 유의성도 중요하다. 즉 비지니스 로직 코드가 보일러플레이트(반복적인 코드 작성을 줄이기 위해 재사용이 가능한 코드)보다 더 중요하다.
테스트를 실패로 바꾸지 않고 기본 어플리케이션 코드를 리팩터링 할 수 있는지에 대한 척도이다.
리팩터링은 식별 할 수 있느 동작을 수정하지 않고 기존 코드를 바꾸는 것을 말한다.
ex) 메서드 이름을 바꾸거나 코드 조각을 새로운 클래스로 추출 하는 것
기반 코드를 수정하면 테스트를 빨간색으로 바뀌게끔 작성이 되어있다면 실제로 기능이 작동하지 않는지는 상관이 없다...
이런 상황을 거짓 양성이라고 한다. 기능은 의도한 대로 작동하지만 테스트는 실패를 나타내는 결과다.
테스트가 지속 간능한 성장을 하는 메커니즘은 회귀 없이 주기적으로 리팩터링하고 새로운 기능을 추가할 수 있는 것이다. 이 때에는 아래와 같은 장점을 가진다.
하지만 거짓 양성을 이 두가지 모두를 방해한다.
테스트와 테스트 대상 시트템(SUT)의 구현 세부 사항이 많이 결합할수록 허위 경보가 더 많이 생긴다.
이 문제의 해결 방법은 해당 구현 세부 사항에서 테스트를 분리하는 것뿐이다.
위의 그림과 같이 구현 세부 사항 대신 최종 결과를 목표로 한다면 거짓 양성을 줄 일 수 있다.
프로젝트가 시작한 직후에는 회귀방지가 리팩터링내성의 필요성이 더 크다.
거짓 양성을 피하는 데에는 리팩터링 내성이 도움이 된다.
회귀 방지와 리팩터링 내성은 테스트 스위트의 정확도를 극대화하는 것을 목표로 한다.
초기에는 리팩터링이 바로 중요하지 않기에 거짓 양성의 중요성이 떨어진다.
하지만 시간이 지나면 코드 베이스는 나빠진다. 점점 복잡해지고 체계성이 떨어지게 된다.
이런 경향을 줄이기 위해 정기적으로 리팩터링을 해야한다. 그렇기에 후반으로 갈 수록 거짓 양성의 중요성이 올라가게된다.
당연하게도 테스트는 빠를 수록 좋다.
유지 보수성 지표는 유지비를 평가하고 아래와 같은 두가지 주요 요소로 구성되어있다.
모든 면에서 좋은 이상적 테스트는 만들 수 없다.
회귀 방지, 리팩터링 내성, 빠른 피드백은 상호 배타적이기 때문에 셋 중 하나를 희생해야 나머지 둘을 최대로 할 수 있다.
극단적 사례를 살펴보자
피라미드의 상단으로 갈 수 록 회귀 방지에 유리한 반면 하단은 실행 속도를 강조한다.
어느 계층도 리팩터링 내성을 포기하지는 않는다.
테스트 피라미드에는 예외를 가지고 있다. 모든 어플리케이션이 비즈니스 규칙이나 기타 복잡도가 거의 없는 기본적인 CRUD작업이라면 테스트는 '피라미드'는 단위 테스트와 통합 테스트의 수가 같고 엔드 투 엔드 테스트가 없는 직사각형 처럼 보일 것이다.
또 외부 의존성 하나만 연결하는 API 또한 예외를 가진다.
테스트를 작성할 때는 블랙박스 테스트가 바람직하지만 테스트를 분석할 때는 화이트 박스 방법을 사용할 수 있다. 코드 커버리지 도구를 사용해서 어떤 코드 분기를 실행하지 않았는지 확인한 다음 코드 내부 구조에 대해 전혀 모르는 것처럼 테스트 해라!
"프로그래밍을 하는 삶에 있어서 불행한 사실은 코드가 자산이 아니라 책임이라는 점이다."