단위 테스트 현황

  • 기업용 애플리케이션 개발 프로젝트는 제품 코드와 테스트 코드 비율을 1:1에서 1:3 정도 된다.
  • 테스트 작성에 그치지 않고 노력 대비 최대의 이익을 이끌어내는 방식으로 단위 테스트를 작성하는 것이 중요하다.

단위 테스트의 목표

  • 코드 조각을 단위 테스트할 수 없으면 설계 품질이 낮은 것이지만, 코드 조각을 단위 테스트할 수 있다고 설계 품질이 좋은 것은 아니다.
  • 단위 테스트 목표는 소프트웨어 프로젝트의 지속 가능한 성장을 가능하게 하는 것이다.
    • 테스트를 작성하지 않으면 코드 베이스에서 무언가를 변경할 때마다 소프트웨어 엔트로피가 증가한다.
    • 소프트웨어 엔트로피가 증가한 다는 것은 개발 속도가 빠르게 감소한다는 것을 뜻한다.
    • 소프트웨어 엔트로피가 증가하면 하나의 버그를 수정하면 더 많은 버그를 양산하고, 소프트웨어의 한 부분을 수정하면 다른 부분들이 고장날 수 있다.
  • 테스트는 안정망 역할을 하며, 대부분의 버그에 대한 보험을 제공하는 도구라 할 수 있다.
  • 테스트의 한 가지 단점은 초반에 노력이 필요하다는 것이다.
    • 하지만 프로젝트 후반에도 잘 성장할 수 있도록 하므로 장기적으로 보면 그 비용을 메울 수 있다.

좋은 테스트와 좋지 않은 테스트를 가르는 요인

  • 모든 테스트를 작성할 필요는 없다.
    • 일부 테스트는 아주 중요하고 소프트웨어 품질에 매우 많은 기여를 한다.
    • 그밖에 테스트는 잘못된 경고가 발생하고, 버그를 알아내는 데 도움되지 않으며, 유지 보수가 어렵고 느리다.
  • 테스트를 작성할 때 테스트의 가치와 유지 비용을 모두 고려해야 한다. 비용 요소는 다양한 활동에 필요한 시간에 따라 결정된다.
    • 기반 코드를 리팩터링할 때 테스트도 리팩터링하라.
    • 각 코드 변경 시 테스트를 실행하라.
    • 테스트가 잘못된 경고를 발생시킬 경우 처리하라.
    • 기반 코드가 어떻게 동작하는지 이해하려고 할 때는 테스트를 읽는 데 시간을 투자하라.
  • 테스트 코드도 코드다. 애플리케이션 정확성을 보장하는 것을 목표로 하는 코드베이스의 일부로 봐야 한다.
    • 프로덕션 코드와 마찬가지로 단위 테스트도 버그에 취약하고 유지 보수가 필요하다.

테스트 스위트 품질 측정을 위한 커버리지 지표

  • 커버리지 지표: 테스트 스위트가 소스 코드를 얼마나 실행하는지를 백분율로 나타낸다.
  • 가장 널리 사용되는 두 가지 커버리지 지표: 코드 커버리지, 분기 커버리지
  • 코드 커버리지기 너무 적을 떄는 테스트가 충분치 않다는 증거다.
  • 하지만 테스트 커버리지가 높다고 충분하다는 뜻은 아니다.

코드 커버리지 지표에 대한 이해

  • 코드 커버리지 = 제품 코드 라인 수 / 전체 라인 수
  • 코드가 작을수록테스트 커버리지 지표는 더 좋아지는데, 이는 라인 수만 처리하기 때문이다.
  • 코드 커버리지가 높다고 충분히 테스트 된 것이 아니다.
  • 아래 두 코드에서 input이 “abc"에 대한 테스트만 있어도 아래가 위보다 코드 커버리지가 높다.
fun isStringLOng(input: String): Boolean {  
   if (input.length > 5) return true  
   return false
}
fun isStringLOng(input: String): Boolean {  
   return input.length > 5  
}

분기 커버리지 지표에 대한 이해

  • 분기 커버리지 = 통과 분기 / 전체 분기 수
  • 분기 커버리지 지표는 분기 개수만 다루며, 해당 분기를 구현하는 데 얼마나 코드가 필요한지 고려하지 않는다.

커버리지 지표에 관한 문제점

  • 테스트 스위트의 품질을 결정하는 데 어떤 커버리지 지표도 의존할 수 없는 이유
    • 테스트 대상 시스템의 모든 가능한 결과를 검증한다고 보장할 수 없다.
    • 외부 라이브러리의 코드 경로를 고려할 수 있는 커버리지 지표는 없다.

특정 커버리지 숫자를 목표로 하기

  • 커버리지 지표를 보는 가장 좋은 방법은 지표 그자체로 보는 것이며, 목표로 여겨서는 안 된다.
  • 특정 커버리지 숫자를 목표로 하는 것은 단위 테스트의 목표와 반대되는 그릇된 동기 부여가 된다.
  • 커버리지 지표는 종흔 부정 지표지만 나쁜 긍정 지표다.

무엇이 성공적인 테스트 스위트를 만드는가?

  • 테스트 스위트가 얼마나 좋은지는 자동으로 확인할 수 없다. 개인 판단에 맡겨야 된다.
  • 성공적인 테스트 스위트는 다음과 같은 특성을 갖고 있다.
    • 개발 주기에 통합돼 있다.
    • 코드베이스에서 가장 중요한 부분만을 대상으로 한다.
    • 최소한의 유지비로 최대의 가치를 끌어낸다.

개발 주기에 통합돼 있음

  • 모든 테스트는 개발 주기에 통합돼야 한다.
  • 이상적으로는 코드가 변경될 때마다 아무리 작은 것이라도 실행해야 한다.

코드베이스에서 가장 중요한 부분만을 대상으로 함

  • 시스템의 가장 중요한 부분에 단위 테스트 노력을 기울이고, 다른 부분은 간략하게 또는 간접적으로 검증하는 것이 좋다.
  • 대부분의 애플리케이션에서 가장 중요한 부분은 비즈니스 로직(도메인 모델)이 있는 부분이다.
    • 다른 모든 부분은 세 가지 범주로 나눌 수 있다.
      • 인프라 코드
      • 데이터베이스나 서드파티 시스템과 같은 외부 서비스 및 종속성
      • 모든 것을 하나로 묶는 코드
  • 통합 테스트와 같이 일부 테스트는 도메인 모델을 넘어 코드베이스의 중요하지 않은 부분을 포함해 시스템이 전체적으로 어떻게 작동하는지 확인할 수 있다.

최소 유지비로 최대 가치를 끌어냄

  • 가치가 유지비를 상회하는 테스트만 스위트에 유지하는 것이 중요하다.
    • 가치 있는 테스트 식별하기
    • 가치 있는 테스트 작성하기
  • 가치가 높은 테스트를 식별하려면 기준틀이 필요하다. 가치있는 테스트를 작성하려면 코드 설계 기술도 알아야 한다.

이 책을 통해 배우는 것

  • 테스트 스위트 내의 모든 테스트를 분석하는 데 사용할 수 있는 기준틀
  • 기존 단위 테스트 기술과 실천
  • 제품 코드와 관련 테스트 스위트를 리팩터링하는 방법
  • 단위 테스트를 다양한 스타일로 적용하는 방법
  • 통합 테스트로 시스템 전체 동작 검증하기
  • 단위 테스트 안티 패턴 식별하고 예방하기
  • 통합 테스트, 엔드 투 엔드 테스트