본문 바로가기

Java/Test Driven Development

2-2. 테스트와 설계

해당 포스트는 이규원님의 "Spring Boot TDD" 강의를 기반으로 작성하였습니다.

 

Spring Boot TDD - 입문부터 실전까지 정확하게| 이규원 - 인프런 강의

현재 평점 5점 수강생 364명인 강의를 만나보세요. 더 빠르고 더 견고하게 Spring Boot 응용프로그램을 개발하세요. 정확한 이론 설명과 실무 수준의 연결된 실습을 통해 HTTP API 응용프로그램 개발에

www.inflearn.com


1. 테스트 시나리오

테스트 시나리오는 제품이 갖춰야 할 기능을 검증하는 작은 단위입니다.
제품의 요구사항을 표현하는 방법은 아주 많은데, 테스트 시나리오도 그 중에 하나입니다.
대부분의 테스트 시나리오는 클라이언트 입장에서 작성됩니다. 그리고 다른 요구사항 작성 방법처럼 테스트 시나리오는 제품의 가치와 품질에 큰 영향을 주는 중요한 요소입니다.

이 테스트 시나리오는 사실 우리 모두에게 그리 낯선 것은 아닙니다.
프로그래머는 심지어 테스트 시나리오라는 말을 한 번도 들어본 적이 없는 프로그래머도 의식적으로 또는 무의식적으로 문서화하든 머릿속에서만 정리하든 명확하게 또는 희미하게 테스트 시나리오를 구성합니다

2. 자동화된 테스트의 특징

자동화된 테스트는 테스트 시나리오의 구체적인 흐름이 실행할 수 있는 코드의 형태로 작성된 문서입니다.
자동화된 테스트는 사람이 수동으로 테스트 시나리오를 검증하는 것에 비해서 비용이 훨씬 적게 듭니다
그리고 자동화된 테스트는 반복적으로 실행하기가 쉽습니다.
뿐만 아니라 사람에 비해서 조성된 테스트 환경 외에 주변 영향을 덜 받기 때문에 테스트 시나리오 검증 결과에 신뢰도가 높습니다.

 

3. 설계와 테스트의 관계

설계 관점에서는 이 자동화된 테스트가 어떤 특징을 가질까요?

TDD와 관련해서 많은 활동을 하는 프로그래머 마크 시마는 몇 년 전에 본인의 블로그에서 이런 말을 했습니다. "단위 테스트는 운영 API의 첫 번째 클라이언트입니다.

테스트는 시스템이 제공하는 기능을 검증하기 위해서 시스템이 노출하는 인터페이스에 의존하고 시스템의 기능을 사용합니다.
이게 바로 클라이언트가 하는 일이죠
이건 TDD를 사용하지 않더라도 변하지 않는 사실입니다

클라이언트는 공개된 인터페이스 설계에만 의존하고 시스템 내부에 감춰진 구현 설계에는 의존하지 않는 것이 원칙입니다

 

4. 구현 설계에 의존하는 테스트와 구현 설계 변경의 여파

구현 설계는 시스템 내부에서 인터페이스를 통해 제공되는 기능을 실현하는 부분입니다. 인터페이스 설계가 클라이언트와의 소통을 담당한다면, 구현 설계는 그 뒤에서 실제 동작을 처리합니다. 그러나 구현 설계는 코드 양이 많고 변경이 잦은 특성을 가집니다.

  • 변경의 자연스러움: 구현 설계는 대안 폭이 넓어(예: 알고리즘 최적화, 코드 구조 개선) 자주 수정됩니다. 이는 시스템 적응성을 높이는 데 필요합니다.
  • 문제의 출발점: 클라이언트가 구현 설계에 의존하면 변경이 어렵습니다. 인터페이스 설계처럼 클라이언트 영향이 크지만, 구현 설계의 경우 코드 규모가 커 비용이 더 많이 듭니다.
  • 클라이언트 범위: 클라이언트는 사용자나 외부 시스템뿐만 아니라 테스트 코드도 포함합니다. 테스트가 구현 설계에 의존하면 변경 시 더 큰 문제가 발생합니다.
  • 전체 영향: 시스템이 주변 환경 변화(예: 요구사항 수정)에 적응하지 못하면 엔지니어링 효율이 떨어집니다. 비용 증가와 시간 지연으로 프로젝트 전체가 지연될 수 있습니다.

 

5. 구현 설계 의존성의 문제점: 변경 여파 확대

  클라이언트(특히 테스트)가 구현 설계에 의존하면 변경 시 내부뿐만 아니라 외부까지 영향이 미칩니다. 이는 "원칙 위배"로, 구현 설계는 클라이언트가 의존하지 않아야 한다는 규칙을 어기는 것입니다.

  • 내부 영향: 구현 설계 변경은 시스템 내부에 자연스러운 파급 효과를 줍니다. 이는 예상 가능하고 비용이 적게 듭니다(예: 코드 리팩터링).
  • 외부 확산: 클라이언트(테스트)가 구현에 의존하면 여파가 퍼집니다. 테스트가 잘못된 결과를 출력하거나 컴파일 실패 발생.
  • 테스트 다중성 문제: 하나의 기능은 여러 테스트 시나리오를 가집니다. 구현 의존 테스트가 많으면 변경 시 모든 테스트가 망가집니다.
  • 비용 증가 이유:
    • 구현 설계는 인터페이스보다 코드가 방대해 수정 범위가 큽니다.
    • 테스트 수정 작업이 추가되며, 기능 하나당 여러 테스트가 영향을 받아 전체 비용 폭증.
  • 효율 저하: 시스템이 변화에 적응 못해 엔지니어링 효율 감소. 개발 속도 저하, 유지보수 어려움.

 

6. 실무 사례와 오해: TDD·테스트에 대한 실망

 과거 경험처럼 테스트 이해도가 낮을 때 구현 의존 테스트를 만들면 고통스러운 상황이 발생합니다. 이는 많은 프로그래머가 겪는 문제로, 잘못된 설계 관리가 원인입니다.

  • 발생 과정: 구현 변경 → 테스트 대량 실패 → 수정 반복. 괴로운 경험이 쌓이면 TDD나 테스트 자체에 실망·비난으로 이어집니다.
  • 근본 원인: 테스트가 구현에 의존하도록 설계한 탓. 무고한 TDD/테스트가 누명을 씁니다.
  • 피하는 방법: 테스트를 인터페이스나 기능 수준에 의존하게 설계. 구현 변경 시 테스트 안정성 유지.

 

'Java > Test Driven Development' 카테고리의 다른 글

2-4. TDD에 대한 오해  (2) 2025.07.22
2-3. TDD 절차  (0) 2025.07.22
2-1. 인터페이스 설계와 구현 설계  (1) 2025.07.22
1-1. 엔지니어링과 원칙  (1) 2025.07.22
Practical Testing: 실용적인 테스트 가이드  (0) 2024.06.28