좋은 단위 테스트의 4대 요소

log.yunsik·2023년 1월 4일
0

좋은 단위 테스트의 4 가지 특성

  • 회귀 방지
  • 리팩터링 내성
  • 빠른 피드백
  • 유지 보수성

회귀 방지

회귀 : 코드를 수정한 후 기능이 의도한 대로 작동하지 않는 경우

테스트에서 실행되는 코드가 많을수록 회귀를 방지할 가능성이 높다.
회귀를 방지하기 위해 테스트가 가능한 많은 코드를 실행하는 것을 목표로 하자.

복잡하고 비지니스에 중요한 기능일 수록 버그가 큰 피해를 입히기 때문에 테스트를 꼭 하자.

단순한 코드는 실수할 여지가 많지 않기 때문에 테스트하는 가치가 거의 없다.

라이브러리, 프레임워크, 외부 시스템을 테스트 범주에 포함시켜 의존성이 올바른지 확인한다.

리팩터링 내성

리팩터링 내성 : 테스트를 빨간색(실패)으로 바꾸지 않고 코드를 리팩터링할 수 있는지에 대한 척도
거짓 양성 : 리팩토링 후 테스트가 실패하지만 기능이 완벽하게 작동하는 상황

거짓 양성은 코드를 리팩터링할 때 즉 구현을 수정하지만 식별할 수 있는 동작은 유지할 때 발생한다.
리팩터링 내성 점수는 테스트에서 얼마나 거짓 양성이 발생하는지 살펴봐야 한다.
프로젝트가 지속 가능하게 성장하는 방법은 회귀 없이 주기적으로 리팩터링 하고 새로운 기능을 추가할 수 있는 것이다.

빠른 피드백

빠른 테스트는 더 많은 테스트를 수행할 수 있고 더 자주 실행할 수 있다.
테스트가 빠르게 실행되면 피드백 루프를 대폭 줄여서 버그 수정 비용을 거의 0 까지 줄일 수 있다.

느린 테스트는 피드백을 느리게 하고 잠재적으로 버그를 뒤늦게 눈에 띄게 해서 버그 수정 비용이 증가한다.
오래 걸리는 테스트는 자주 실행하지 못하기 때문에 잘못된 방향으로 가면서 시간을 더 많이 낭비하게 된다.

유지보수성

유지 보수성 점수는 유지비를 평가한다.

  • 테스트가 얼마나 이해하기 어려운가
    테스트는 코드 라인이 적을수록 읽기 쉽고 필요할 때 변경하는 것도 쉽다.
    그렇다고 테스트 코드를 인위적으로 압축하지 않는다.
    테스트 코드의 품질은 제품 코드만큼 중요하다.
    테스트를 작성할 때 절차를 생략하지 말라.
  • 테스트가 얼마나 실행하기 어려운가
    프로세스 외부 종속성으로 작동하면 데이터베이스 서버를 재부팅하고 네트워크 연결 문제를 해결하는 등 의존성을 상시 운영하는데 시간을 들여야 한다.

이상적인 테스트를 만들 수 있는가?

불가능하다 회귀 방지, 리팩터링 내성, 빠른 피드백은 상호 배타적이기 때문이다.
네 가지 범주 중 하나에서 0점을 받는 테스트는 곱셈 원리이기 때문에 가치 없다.
따라서 특성 중 어느 것도 크게 줄이지 않는 방식으로 최대한 크게 해야 한다.

극단적인 사례 1: 엔드 투 엔드 테스트

엔드 투 엔드 테스트는 최종 사용자 관점에서 시스템을 살펴본다.
많은 코드를 테스트하므로 회귀 방지를 훌륭히 해낸고 거짓 양성에 면역이 돼 리팩터링 내성도 우수하다.
리팩터링은 식별할 수 있는 동작을 변경하지 않으므로 엔드 투 엔드 테스트에 영향을 미치지 않는다.
최종 사용자의 관점에서 기능이 어떻게 동작하는지만 볼 수 있으며 구현 세부사항을 최대한 제거 했다.

엔드 투 엔드 테스트에는 큰 단점은 바로 느린 속도다.
엔드 투 엔드 테스트에만 의존하는 모든 시스템은 피드백을 빨리 받기 어렵다.
회귀 오류와 거짓 양성에 대한 방지를 훌륭히 해내지만 속도가 떨어진다.

극단적인 사례 2: 간단한 테스트

간단한 테스트는 매우 빠르게 실행되고 빠른 피드백을 제공한다.
거짓 양성이 생길 가능성이 상당히 낮기 때문에 리팩터링 내성도 우수하다.

간단한 테스트의 단점은 실수할 여지가 많지 않기 때문에 회귀를 잡아내기 힘들다.
우수한 리팩터링 내성과 빠른 피드백을 제공하지만 회귀 방지가 없다.

극단적인 사례 3: 깨지기 쉬운 테스트

실행이 빠르고 회귀를 잡을 가능성이 높지만 거짓 양성이 많은 테스트를 작성하기가 매우 쉽다.
리팩터링을 견디지 못하고 해당 기능이 고장 났는지 여부와 관계 없이 빨간색으로 바뀌다.

이상적인 테스트를 찾아서: 결론

좋은 단위 테스트의 특성은 곰셈 규칙으로 인해 한 가지 특성이 0에 가까워진다면 전체 가치가 0에 가까워진다.
유지 보수성은 엔드 투 엔드 테스트를 제외하고 처음 세 가지 특성과 상관관계가 없다.
리팩터링 내성은 포기할 수 없다.
엔드 투 엔드 테스트만 쓰거나 테스트가 상당히 빠르지 않은 한 리팩터링 내성을 최대한 많이 갖는 것을 목표로 해야 한다.
따라서 테스트가 얼마나 버그를 잘 찾아내는지(회귀 방지)와 얼마나 빠른지(빠른 피드백) 사이의 선택으로 절충이 귀결된다.
리팩터링 내성을 포기할 수 없는 이유는 테스트가 이 특성을 갖고 있는지 여부는 있거나 없거나 둘 중 하나이기 때문이다.

부록

테스트 장점

  • 결함이 있는 코드가 운영 환경에 배포되기 훨씬 전에 문제를 해결할 수 있다.

  • 코드 변경이 회귀로 이어지지 않을 것이라고 확신하게 된다. 확신이 없으면 리팩터링을 하는데 주저하게 되고 코드 베이스가 나빠질 가능성이 높아진다.

거짓 양성의 원인이 무엇인가?

테스트와 테스트 대상 시스템의 구현 세부 사항이 많이 결합될수록 거짓 양성이 더 많이 생긴다.
거짓 양성을 줄이는 방법은 구현 세부 사항에서 테스트를 분리하는 것 뿐이다.
테스트를 통해 최종 사용자에게 의미 있는 결과를 확인해야 한다.

0개의 댓글