본문으로 건너뛰기

1장 단위 테스트의 기초

이 장에서 다룰 핵심 내용

  • 테스트의 시작접과 종료점 구분
  • 단위 테스트와 작업 단위의 정의
  • 단위 테스트와 통합 테스트의 차이
  • 간단한 예시로 단위 테스트 살펴보기
  • 테스트 주도 개발 이해

핵심: 테스트와 회귀 테스트를 자동화합니다.

1. 누구에게나 처음은 있다.

  • 단위 테스트가 무엇인지 알아야 합니다.
  • 단위 테스트의 신뢰도를 높이려면 다른 종류의 테스트와 명확히 분리할 줄 알아야 합니다.
  • TDD를 소개합니다.

2. 단위 테스트 정의

  • 단위 테스트는 컴퓨터 프로그래밍에서 예제 코드의 특정 모듈이 의도된 대로 정확히 작동하는지 검증하는 입니다.
  • 테스트를 작성할 대상은 테스트 중인 주제, 시스템, 테스트 대상입니다.
  • 필자는 단위 테스트에서 ‘단위’는 시스템 내 ‘작업 단위’ 또는 ‘사용 사례’를 의미한다고 합니다. (단순히 함수 이상의 의미일 수 있습니다)
  • 작업 단위에는 시작을 의미하는 진입점과 끝을 의미하는 종료점이 존재합니다.

3. 진입점과 종료점

  • 작업 단위에는 항상 하나의 진입점과 하나 이상의 종료점이 있습니다.
  • 작업 단위는 함수 하나 일수도 있고, 여러 함수를 의미할 수도 있습니다.
  • 함수가 아니어도 모듈이나 컴포넌트가 작업 단위가 될 수 있습니다
  • 진입점은 작업단위가 시작되는 것입니다. (가령, 함수라면 함수 호출이 되겠습니다)
  • 종료점은 작업단위가 끝나는 것입니다.
    • 값이나 오류를 반환
    • 상태 값을 변경
    • 다른 서드 파티를 호출(의존성 호출, 제어할 수 없는 것)
  • 진입점과 종료점은 같은수도 다를수도 있습니다.
    • 같은 경우: 함수를 호출하고 값을 반환 받습니다.
    • 다른 경우: 함수를 호출하고 함수 내부에서 상태값을 변경합니다.

4. 종료점 유형

  • 단위 테스트는 작업 단위를 호출하고, 그 작업 단위의 최종 결과로서 하나의 특정 종료점을 테스트 검증 목표로 사용합니다.
  • 최종 결과가 테스트가 검증하고자 하는 바와 다르다면 단위 테스트는 실패합니다.
  • 단위 테스트 범위는 진입점과 종료점 사이에 사용되는 함수와 모듈의 수에 따라 함수 하나에서 여러 모듈이나 구성 요소에 이를 수 있습니다.

5. 다른 종료점, 다른 기법

  • 각 종료점마다 테스트를 만들어 분리하는 것이 코드 관리 측면에서 유리합니다.
  • 종료점 종류에 따라 테스트 방법도 다르게 가져갑니다.
    • 반환 값이 있는 종료점: 실행 결과 값을 확인
    • 상태 값을 변경하는 종료점: 상태 값이 바뀌었는지 확인하고, 이전에 호출한 것을 다시 호출하여 모든 것이 의도대로 동작하는지 확인
    • 서드 파티를 호출하는 종료점: 모의 객체를 만들어 테스트 결과를 임의로 조작

6. 처음부터 테스트 코드 작성

  • 테스트 프레임워크 없이 테스트를 작성하고 있습니다. 책 참고

7. 좋은 단위 테스트의 특징

  • 좋은 단위 테스트의 특징
    • 빠르게 실행되어야 합니다.
    • 테스트 환경을 일관되게 유지하고, 테스트 결과가 항상 예측 가능해야 합니다.
    • 다른 테스트와 완전히 독립적으로 실행되어야 합니다.
    • 시스템 파일, 네트워크, 데이터베이스가 없어도 메모리 내에서 실행되어야 합니다.
      • 데이터베이스나 다른 의존성을 스텁으로 대체하기
    • 가능한 한 동기적인 흐름으로 실행되어야 합니다. (가능하면 병렬 스레드를 사용하지 않아야 합니다)
      • 비동기 처리를 동기적 테스트로 흉내 내기
  • 모든 테스트가 이런 특성을 전부 만족하는 것은 불가능에 가깝습니다.
    • 많은 조건을 충족하도록 만들려고 노력합니다.
    • 통합 테스트로 만드는 것도 하나의 방법입니다.
  • 단위 테스트의 조건
    • 2주, 2개월, 2년 전에 만든 테스트가 여전히 잘 돌아가는가?
    • 내가 2개월 전에 작성한 테스트를 팀 내 다른 동료가 실행했을 때 문제없이 결과를 받을 수 있는가?
    • 내가 만든 테스트가 수분 내로 전부 실행되는가?
    • 버튼 하나만 눌러서 내가 작성한 모든 테스트를 실행할 수 있는가?
    • 기본적인 테스트를 몇 분 내로 작성할 수 있는가?
    • 다른 팀 코드에 버그가 있어도 내 테스트는 통과하는가?
    • 내 테스트는 다른 실행 환경에서 실행해도 동일한 결과를 보장하는가?
    • 데이터베이스나 네트워크, 배포 없이도 내 테스트는 동작하는가?
    • 하나의 테스트를 삭제, 이동, 변경해도 다른 테스트는 영향을 받지 않고 잘 실행되는가?

8. 통합 테스트

  • 통합 테스트는 앞서 언급한 좋은 단위 테스트 조건 중 하나라도 충족하지 못하는 모든 테스트를 의미합니다.
    • 현재 시간을 가져오는 newDate()를 사용 (실제 시스템 시간 사용)
    • 실제 데이터베이스를 사용 (메모리에서만 실행되는게 아님) → 스텁을 사용
  • 통합 테스트는 한 번에 너무 많이 테스트하는 것이 문제입니다.
    • 테스트에 실패했을 때, 어디에서 실패한 것인지 원인 파악이 어렵습니다.
  • 요약하자면 통합 테스트는 실제 의존성을 사용하고, 단위 테스트는 작업 단위를 의존성에서 격리시켜 항상 일관된 결과를 받을 수 있도록 하여 작업 단위의 모든 측면을 쉽게 조작할 수 있게 합니다.
    • 통합 테스트는 회귀에 실패할 수 있습니다.
    • 단위 테스트로 신뢰를 쌓아서 레거시 코드를 손쉽게 수정할 수 있습니다.
    • 테스트는 빨라야 합니다.
    • 모든 테스트를 한 번에 실행하도록 환경을 구성해야 합니다.
    • 테스트를 손쉽게 작성할 수 있어야 합니다. (단위 테스트는 간단하기에 가능합니다)
    • 외부 의존성은 스텁을 사용해서 의존성을 없앱니다.
    • 단위 테스트는 다른 테스트들과 독립적으로 실행되어야 합니다.

9. 최종 정리

단위 테스트는 진입점을 통해 단위를 호출한 후 그 종료점을 확인하는 자동화된 코드다. 단위 테스트는 거의 항상 단위 테스트 프레임워크를 사용하여 쉽게 작성할 수 있고 빠르게 실행할 수 있다. 잘 작성된 단위 테스트는 신뢰성이 높고 가독성도 좋아서 유지 보수하기에 용이하다. 우리가 운영하는 코드가 변경되지 않는 한 동일한 결과를 보장한다.

10. 테스트 주도 개발(TDD)

  • 언제 테스트를 작성할 것인가?
    • 코드 머지하기 직전
    • 코딩 전에 단위 테스트를 작성 (TDD)
  • TDD는 단위 테스트의 대체재가 아닙니다.
    • 좋은 테스트를 작성하는 것은 TDD와 별개의 기술입니다.
  • 기술 자체는 간단합니다.
    1. 구현하고자 하는 기능에 대한 테스트가 일부러 실패하도록 테스트를 작성하거나 기능 자체를 비워 두어 테스트가 실패하도록 만듭니다.
    2. 테스트가 통과할 수 있도록 코드를 수정합니다.
      • 단순하게 수정하고 일단 테스트가 통과되는 것이 우선입니다.
    3. 코드를 리팩토링합니다.
  • 가장 큰 장점은 테스트가 실패하는 것을 시작으로 테스트 코드의 수정 없이 기능 수정만으로 테스트를 통과하도록 한다는 것입니다.
    • 테스트 자체를 검증, 테스트가 예상대로 실패해야 하는데 통과하면 테스트에 버그가 있거나 잘못된 코드를 테스트하고 있다는 의미입니다.
  • TDD의 세 가지 핵심 전략
    • 좋은 테스트 코드 작성 (이 책에서 배울 내용)
    • 테스트부터 작성합니다.
    • 원칙에 따라 설계 (테스트와 프로덕션 코드를 잘 설계한다)

Wrap Up

  • 단위 테스트는 작업 단위의 진입점과 종료점을 검증하는 자동화된 테스트입니다.
  • 각 종료점 유형(반환 값, 상태 변경, 외부 호출)에 따라 적절한 테스트 기법을 적용해야 합니다.
  • 좋은 단위 테스트는 빠르고, 예측 가능하며, 독립적으로 실행되어야 합니다.
  • 통합 테스트는 실제 의존성을 사용하며, 단위 테스트는 의존성을 격리시킵니다.
  • TDD는 테스트 실패 → 코드 수정 → 리팩토링의 순환 과정을 통해 개발을 진행합니다.

Summary

단위 테스트는 작업 단위의 진입점과 종료점을 검증하는 자동화된 테스트로, 빠르고 독립적이며 예측 가능한 결과를 제공하여 코드의 신뢰성을 보장합니다.

Reference