411. 리그레션 테스트 자동화 및 선택적 수행 (Retest All vs Selective)

⚠️ 한정된 시간과 컴퓨팅 자원 내에서 회귀 테스트의 효율성을 극대화하기 위해, 테스트 범위를 결정하는 두 가지 핵심 전략(전체 테스트와 선택적 테스트)과 이를 가능하게 하는 자동화 프레임워크 설계에 대해 다룹니다.

핵심 인사이트 (3줄 요약)

  1. 본질: 리그레션 테스트 전략은 '안전성을 위해 모든 것을 다시 테스트할 것인가(Retest All)' 아니면 '효율성을 위해 변경된 코드와 연관된 테스트만 골라낼 것인가(Selective)' 사이의 트레이드오프(Trade-off)를 다루는 최적화 문제다.
  2. 가치: 지속적 배포 (Continuous Deployment) 환경에서는 테스트 실행 시간이 곧 릴리즈 리드타임(Lead Time)을 결정한다. 선택적 수행은 테스트 피드백을 수십 분에서 수 분 단위로 단축시켜 애자일(Agile) 조직의 민첩성을 유지한다.
  3. 기술 체계: 선택적 수행을 위해서는 콜 그래프(Call Graph) 기반의 '영향도 분석(Impact Analysis)' 기술이 필수적이며, 이는 CI/CD (Continuous Integration / Continuous Deployment) 파이프라인에서 테스트 자동화 도구와 결합하여 동적으로 테스트 스위트(Test Suite)를 구성한다.

Ⅰ. 회귀 테스트의 딜레마: 완벽함 vs 신속함

  • 개념: 소프트웨어의 규모가 커지면 테스트 케이스(Test Case)의 수도 수만 개로 증가한다. 코드를 한 줄 고칠 때마다 수만 개의 테스트를 모두 실행하는 것은 논리적으로는 가장 완벽한 방어책이지만, 물리적인 시간과 비용 측면에서는 재앙에 가깝다. 이 딜레마를 해결하기 위해 '전체 재테스트 (Retest All)'와 '선택적 테스트 (Selective Testing)' 전략이 대립한다.

  • 필요성: 만약 테스트 실행에 5시간이 걸린다면, 개발자는 코드를 수정한 후 결과를 확인하기 위해 다음 날까지 기다려야 한다. 이는 개발자의 몰입(Context Flow)을 깨뜨리고, 하루에 여러 번 배포해야 하는 현대의 마이크로서비스 아키텍처 (Microservices Architecture, MSA) 환경에 정면으로 위배된다.

  • 테스트 최적화의 목표: 따라서 시스템의 핵심은 "결함 검출률(Fault Detection Rate)은 100%에 가깝게 유지하면서, 테스트 실행 시간(Execution Time)은 최소화하는 스위트를 동적으로 구성"하는 것이다.

  • 📢 섹션 요약 비유: 마치 공항에서 모든 승객의 짐을 하나하나 다 열어보는 것(Retest All)이 가장 안전하지만 비행기가 지연되는 문제가 발생하므로, 폭발물 탐지견과 X-ray 스캐너를 통해 의심스러운 짐만 골라내어 정밀 검사(Selective)하는 것과 같습니다.


Ⅱ. 전략 1: 전체 테스트 (Retest All)

  • 정의: 기존에 만들어진 모든 테스트 케이스를 예외 없이 다시 실행하는 가장 직관적이고 무식(Brute-force)하지만 확실한 방법이다.
  • 적용 시기:
    • 운영 체제(OS)나 데이터베이스 관리 시스템(DBMS), 컴파일러 버전을 업그레이드했을 때.
    • 전역 변수(Global Variable)나 코어 프레임워크, 공통 유틸리티 등 파급 효과를 가늠하기 힘든 근본적인 변경이 일어났을 때.
    • 메이저 버전 릴리즈 전날 밤, 최종 승인(Sign-off)을 위한 나이트리 빌드(Nightly Build) 시.
┌────────────────────────────────────────────────────────┐
│             전체 테스트 (Retest All)의 특징               │
├────────────────────────────────────────────────────────┤
│                                                        │
│  [변경 사항] ───> [코드 베이스]                         │
│                        │                               │
│  [테스트 스위트] (TC 1 ~ TC 10,000)                    │
│    │                                                   │
│    ├─> 모듈 A (영향 O) ───> TC 1 ~ 1,000 실행          │
│    ├─> 모듈 B (영향 O) ───> TC 1,001 ~ 2,000 실행      │
│    ├─> 모듈 C (영향 X) ───> TC 2,001 ~ 9,000 실행 (낭비)│
│    └─> 모듈 D (영향 X) ───> TC 9,001 ~ 10,000 실행 (낭비)│
│                                                        │
│  * 결과: 완벽한 안전성 보장, 극심한 시간/자원 낭비 발생        │
└────────────────────────────────────────────────────────┘

[다이어그램 해설] 이 방식은 변경된 코드와 전혀 연관이 없는 모듈 C와 D의 테스트 케이스까지 모조리 실행한다. 안전성 측면에서는 이보다 좋을 수 없으나, 리소스가 막대하게 소모된다. 실무에서는 이러한 전체 테스트를 개발자가 코드를 커밋할 때마다 수행하지 않고, 하루 일과가 끝난 자정(Midnight)에 스케줄링하여 수행하는 나이트리 빌드(Nightly Build) 전략으로 우회하여 사용한다.

  • 📢 섹션 요약 비유: 집에 도둑이 들었을지 모른다는 생각에, 방 하나에만 창문이 열려 있었음에도 불구하고 지하실부터 다락방까지 집 안의 모든 구석을 플래시를 켜고 샅샅이 뒤지는 가장 보수적인 순찰 방식입니다.

Ⅲ. 전략 2: 선택적 테스트 (Selective Regression Testing)

  • 정의: 변경된 코드와 수학적, 논리적 의존성(Dependency)이 있는 부분만을 도출하여 연관된 테스트 케이스만 선별적으로 실행하는 최적화 기법이다.
  • 동작 메커니즘:
    1. 코드 변경 식별 (Change Identification): Git Diff 등을 통해 이전 버전과 비교하여 정확히 어느 파일, 어느 함수가 변경되었는지 식별한다.
    2. 영향도 분석 (Impact Analysis): 컴파일러의 콜 그래프(Call Graph)나 AST (Abstract Syntax Tree)를 분석하여 변경된 함수를 호출하는 모든 상위 모듈을 추적한다.
    3. 테스트 케이스 매핑 (Test Case Mapping): 도출된 영향 반경 내의 모듈들을 검증하는 테스트 케이스들의 교집합을 추출한다.
┌─────────────────────────────────────────────────────────────┐
│          콜 그래프(Call Graph) 기반 선택적 테스트 메커니즘        │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   [변경 지점] : `CalculateDiscount()` 함수 변경                 │
│                                                             │
│   1. 영향도 추적 (상향식 콜 그래프 분석)                          │
│      CalculateDiscount()                                    │
│       ▲            ▲                                        │
│       │            │                                        │
│  [Cart.js]     [Payment.js]   [UserProfile.js] (영향 없음)     │
│       ▲            ▲                                        │
│       │            │                                        │
│   (TC_101)      (TC_205)         (TC_301 생략)                │
│   (장바구니)     (결제 검증)        (프로필 조회)                 │
│                                                             │
│   2. 동적 스위트 생성: Suite = { TC_101, TC_205 }             │
│   3. CI 실행: 시간 90% 단축, 피드백 속도 극대화                  │
└─────────────────────────────────────────────────────────────┘

[다이어그램 해설] 할인 로직(CalculateDiscount)을 수정했을 때, 시스템은 이 함수를 참조하는 Cart(장바구니)Payment(결제) 모듈이 영향을 받을 것이라 판단한다. 반면 할인 로직과 전혀 무관한 UserProfile(사용자 프로필) 모듈은 영향도 분석에서 배제된다. 결과적으로 10,000개의 테스트 중 Cart와 Payment에 관련된 1,000개의 테스트만 선별되어 실행되므로, 개발자는 5시간이 아닌 30분 만에 안전성 피드백을 받을 수 있다.

  • 📢 섹션 요약 비유: 수돗물 파이프 하나를 교체했을 때, 도시 전체의 수도관을 점검하는 대신 그 파이프와 직접 연결된 아파트 단지들의 수압과 녹물 여부만 빠르게 점검하여 효율성을 극대화하는 방식입니다.

Ⅳ. 전략 3: 우선순위 및 위험 기반 테스트 (Test Case Prioritization)

  • 정의: 선택적 테스트로 걸러낸 스위트조차 너무 클 경우, 비즈니스 리스크와 결함 발생 이력을 바탕으로 테스트 케이스에 가중치(우선순위)를 부여하여 가장 중요한 것부터 실행하는 기법이다.
  • 우선순위 산정 기준 (Metrics):
    1. 비즈니스 크리티컬리티 (Business Criticality): 결제, 로그인, 회원가입 등 시스템 마비 시 회사에 즉각적인 금전적 손실을 가져오는 핵심 흐름 (P0).
    2. 결함 밀도 (Defect Density): 과거에 버그가 자주 발생했던 취약한 컴포넌트를 테스트하는 케이스.
    3. 코드 커버리지 (Code Coverage): 한 번 실행했을 때 최대한 많은 소스 코드를 훑고 지나가는 굵직한 테스트 케이스.
우선순위유형 (Tier)실행 시점포함되는 내용
Tier 0Smoke Test (BVT)매 커밋 직후 (1분 내)서버 기동, 로그인, 메인 페이지 로딩 등 최중요 기능. 실패 시 즉각 빌드 파기.
Tier 1Core Regression코드 병합 시 (10분 내)결제, 데이터 저장 등 주요 비즈니스 트랜잭션.
Tier 2Full Selective일 1~2회 (1시간 내)변경점과 연관된 모든 엣지 케이스(Edge Case) 및 UI 검증.
Tier 3Retest All릴리즈 전날 (밤새)100% 전체 테스트, 스트레스 테스트.
  • 📢 섹션 요약 비유: 응급실에서 환자가 몰려올 때 접수 순서가 아니라 생명이 위독한 정도(우선순위)에 따라 중증 외상 환자(Tier 0)부터 먼저 치료하여 최악의 사태를 막는 트리아지(Triage) 시스템과 같습니다.

Ⅴ. 자동화 환경 구축 (CI 파이프라인 최적화)

선택적 테스트와 우선순위 기반 테스트는 인간이 직접 계산해서 실행할 수 없다. 이는 최신 CI (Continuous Integration) 프레임워크와 결합될 때만 의미가 있다.

  1. 분산 병렬 처리 (Distributed Parallel Execution):

    • 선택된 테스트 스위트가 여전히 크다면, 쿠버네티스 (Kubernetes)나 AWS EC2와 같은 클라우드 인프라를 활용하여 수십 대의 컨테이너에 테스트 케이스를 쪼개어 동시에 병렬로 실행한다. 1시간 걸릴 테스트를 10대의 노드로 나누어 6분 만에 완료하는 기법이다.
  2. 플래키 테스트 (Flaky Test) 격리:

    • 코드가 정상인데도 네트워크 지연이나 DB 타이밍 이슈로 인해 무작위로 실패하는 테스트를 플래키 테스트라고 한다. 자동화의 신뢰도를 갉아먹는 주범이므로, CI 파이프라인은 실패한 테스트를 자동으로 2~3회 재시도(Retry)하고, 그래도 실패하면 해당 테스트를 격리(Quarantine)하여 신뢰성을 유지해야 한다.
  • 📢 섹션 요약 비유: 아무리 훌륭한 분류법이 있어도 사람이 손으로 분류하면 느립니다. 이 전략들을 우편물 자동 분류 컨베이어 벨트(CI 파이프라인)에 올려, 기계가 초당 수천 개의 테스트를 병렬로 분류하고 실행하도록 만드는 공장화 작업입니다.

👶 어린이를 위한 3줄 비유 설명

  1. 매일 아침 학교에 가기 전에 가방을 챙길 때, 가방 안의 모든 책과 연필을 다 꺼내서 확인하는 건 너무 오래 걸려요(전체 테스트).
  2. 그래서 오늘 시간표에 바뀐 과목표만 보고, 수학이랑 미술 시간표가 바뀌었으면 그 두 과목의 준비물만 쏙쏙 확인하는 게 훨씬 빠르겠죠? (선택적 테스트).
  3. 리그레션 테스트 전략은 컴퓨터 프로그램이 고장나지 않았는지 확인할 때, 무식하게 다 검사할지 똑똑하게 바뀐 부분만 골라서 검사할지 작전을 짜는 거랍니다!