테스트 주도 개발: DAMP 원칙과 효과적인 테스트 전략

TDD: Why does it fail? - Michael Milewski

작성자
Ruby Australia
발행일
2025년 08월 11일

핵심 요약

  • 1 테스트는 'Arrange-Act-Assert' 패턴을 따르며, `let`이나 `described_class` 사용을 지양하여 자체 포함적이고 명확하게 작성해야 합니다.
  • 2 DRY(Don't Repeat Yourself)보다 DAMP(Descriptive And Meaningful Phrases) 원칙을 적용하여 테스트 코드의 가독성과 이해도를 높이는 것이 중요합니다.
  • 3 외부 시스템은 모킹하고, 불필요한 데이터는 배제하며, 테스트 실패 메시지는 구체적으로 작성하여 테스트의 효율성과 신뢰성을 확보해야 합니다.

도입

Michael Movki는 Ruby 및 Rails 개발 경험을 바탕으로 테스트 주도 개발(TDD)에 대한 깊이 있는 통찰을 공유합니다. 그는 Martech에서 AI 기반 플랫폼을 개발하며, 급변하는 기술 환경 속에서 개발자들이 직면하는 변화의 어려움을 언급합니다. 본 강연은 기존의 테스트 방식에 대한 재고를 촉구하며, 보다 효율적이고 유지보수 가능한 테스트 코드 작성법을 모색하는 데 초점을 맞춥니다. 특히, 인지 부하를 줄이고 생산성을 높이는 테스트 철학을 제시하여 청중에게 새로운 관점을 제공하고자 합니다.

모든 소프트웨어는 ‘입력-처리-출력’의 함수로 볼 수 있으며, 이 본질은 테스트의 핵심 원리를 이룹니다. 강연자는 CSV 파일에서 통계 데이터를 추출하는 간단한 예시를 통해, 테스트 없는 코드 배포가 리팩토링 및 확장 시 심각한 문제를 야기하고 결국 운영 환경에서 실패할 수 있음을 강조합니다. 그는 ‘테스트 나중 개발’의 함정을 지적하며, AI가 생성한 테스트 코드조차도 확장성이나 유지보수성 측면에서 한계를 가질 수 있음을 보여줍니다.

기존의 ‘Better Specs’ 방식은 described_class, subject, let 등을 활용하여 DRY(Don’t Repeat Yourself) 원칙을 강조하지만, 강연자는 이러한 접근 방식이 테스트 코드의 가독성과 자체 포함성을 저해하여 디버깅 및 이해를 어렵게 한다고 비판합니다. 대신, ‘Even Better Specs’의 원칙을 지지하며 다음과 같은 효과적인 테스트 작성 가이드라인을 제시합니다:

효과적인 테스트 작성 가이드라인

  • 테스트는 자체 포함적이어야 합니다 (Not DRY):
    • 테스트 코드는 복사하여 붙여넣기만 해도 실행 가능해야 합니다.
    • 이는 코드베이스에 익숙하지 않은 개발자나 미래의 자신에게 훌륭한 문서 역할을 합니다.
  • Arrange-Act-Assert 패턴을 따라야 합니다:
    • 테스트의 설정(Given), 실행(When), 검증(Then) 단계가 명확하게 구분되어야 합니다.
  • let 사용을 피해야 합니다:
    • let은 지연 평가(lazy evaluation) 특성으로 인해 복잡한 중첩 컨텍스트에서 추적하기 어려워 자체 포함성을 저해합니다.
  • 공유 예제(Shared Examples)를 지양해야 합니다:
    • 테스트 템플릿 사용보다는 일반 Ruby 메서드를 활용하는 것이 코드 추적 및 이해에 더 효과적입니다.
  • 필요한 데이터만 사용해야 합니다:
    • 테스트에 불필요한 데이터를 생성하지 않음으로써, 테스트의 목적을 명확히 하고 ‘null과 null 비교’와 같은 오류를 방지합니다.
  • 외부 시스템은 반드시 모킹해야 합니다:
    • S3와 같은 외부 서비스 호출을 모킹하여 테스트 속도를 높이고 외부 의존성 없이 안정적인 테스트 환경을 구축합니다.
  • described_class 대신 명확한 클래스 이름을 사용해야 합니다:
    • 예외 발생 시 특정 클래스 이름을 검색하여 관련 테스트를 쉽게 찾을 수 있도록 돕습니다.

또한, 강연자는 테스트 실패 메시지가 “true is not false”와 같이 모호하지 않고 구체적인 정보를 제공하도록 작성해야 한다고 조언합니다. 중요하지 않은 테스트 데이터(예: UID, API 키)는 실제 값 대신 00000000-0000-0000-0000-000000000001과 같은 의미 없는 플레이스홀더를 사용하여 테스트의 목적을 명확히 하고, Swagger 문서 생성 시 충돌을 방지하는 사례를 공유합니다. 궁극적으로, 그는 ‘DAMP(Descriptive And Meaningful Phrases)’ 원칙을 강조하며, 테스트 코드에서는 반복을 감수하더라도 명확하고 이해하기 쉬운 것이 DRY보다 중요하다고 주장합니다.

결론

강연자는 테스트 주도 개발의 진정한 가치가 코드를 자신 있게 리팩토링하고 확장할 수 있는 견고한 기반을 제공하는 데 있다고 강조합니다. 이를 위해 그는 시스템 전반의 동작을 보장하는 경량 통합 테스트와 낮은 수준의 리팩토링을 지원하는 단위 테스트의 두 가지 수준의 테스트를 권장합니다. 특히 Ruby on Rails 환경에서 Active Record 모델의 데이터베이스 상호작용을 직접 단위 테스트하기보다는, 핵심 비즈니스 로직을 커맨드 패턴이나 리포지토리 패턴으로 분리하여 테스트의 범위를 명확히 하는 것이 효과적이라고 제안합니다. 궁극적으로, 명확하고 자체 포함적이며 읽기 쉬운 테스트 코드를 작성하는 것이 개발 생산성과 코드 품질을 높이는 핵심임을 역설합니다.

댓글 0

댓글 작성

0/1000
정중하고 건설적인 댓글을 작성해 주세요.

아직 댓글이 없습니다

첫 번째 댓글을 작성해보세요!