구조 기반 테스트 실전 — 커버리지 도구·경로/데이터 흐름·뮤테이션·정적/동적 분석·코드 리뷰
코드 구조를 근거로 테스트를 설계하고 그 충분성을 측정한다. JaCoCo·Istanbul·coverage.py로 실제 커버리지 리포트를 뽑아 해석하고, 경로 테스트와 데이터 흐름(DU-path) 테스트를 설계하며, 뮤테이션 테스트로 테스트가 정말 결함을 잡는지 검증한다. 정적·동적 분석으로 메모리 누수·자원 릭·와일드 포인터를 찾고, 코드 리뷰를 체크리스트와 결함 유형 분류가 있는 테스트 활동으로 운영한다.
★ 커버리지 수치는 테스트의 충분성이 아니라 테스트하지 않은 곳을 보여 준다.
학습 목표
이 모듈 한 줄 요약 — "손으로 세던 것을 도구가 세게 한다". 모듈 3 에서 커버리지를 개념과 손계산으로 배웠다. 여기서는 도구가 그 숫자를 어떻게 만들어 내는지 따라가고, 그 숫자를 얼마나 믿어도 되는지를 다룬다. 100% 가 왜 안심의 근거가 못 되는지가 이 모듈의 중심이다.
모듈 3(레슨 7, 레슨 10)에서 구문·분기·조건·MC/DC 커버리지와 순환 복잡도·기저 경로를 개념과 손계산 으로 배웠고, 모듈 10(레슨 5)에서 커버리지 리포트의 함정을 코드로 확인했다. 이 모듈은 거기서 한 칸 더 나간다. 손으로 세는 대신 도구가 실제로 숫자를 만들어 내는 과정 을 따라가고, 그 숫자가 어디서 거짓말을 하는지, 그리고 숫자를 믿을 수 있게 만들려면 무엇을 더 해야 하는지를 다룬다.
핵심 질문은 하나다. "커버리지 82%"라는 문장에서 우리가 실제로 알 수 있는 것은 무엇인가. 알 수 있는 것은 "18%는 한 번도 실행되지 않았다"뿐이다. 실행된 82%가 제대로 검증됐는지, 정의된 변수가 올바른 경로로 사용됐는지, 테스트가 결함을 만났을 때 정말 빨갛게 변하는지는 커버리지 숫자가 답하지 못한다. 이 모듈은 그 빈칸을 메우는 네 가지 도구를 다룬다 — 경로·데이터 흐름 테스트로 설계를 촘촘하게 하고, 뮤테이션 테스트로 테스트의 검출력을 측정 하고, 정적·동적 분석으로 실행만으로는 안 보이는 결함 을 찾고, 코드 리뷰를 기록되는 테스트 활동 으로 운영한다.
도구 실습은 JVM(JaCoCo·PIT), JavaScript(Istanbul/nyc·Stryker), Python(coverage.py), C/C++(ASan·Valgrind)를 오간다. 언어를 배우는 것이 목적이 아니라, 어떤 스택에 가도 "이 도구는 무엇을 계측하고 무엇을 못 보는가"를 스스로 판별 할 수 있게 하는 것이 목적이다. 그래서 각 레슨은 명령어와 설정 파일을 그대로 쓸 수 있는 형태로 싣고, 리포트의 각 열이 무엇을 세는 숫자인지까지 내려간다.
마지막 레슨은 도구가 아니라 사람이다. 정적 테스트 중 가장 비용 대비 효과가 큰 활동은 여전히 코드 리뷰이고, QA가 리뷰에 참여하는 방식은 개발자와 달라야 한다. 리뷰에서 나온 질문을 테스트 케이스로 바꾸고, 리뷰에서 잡힌 결함을 유형으로 분류해 다음 리뷰 체크리스트를 진화시키는 순환을 만든다.
완료 후 할 수 있는 것
- JaCoCo·Istanbul(nyc)·coverage.py로 실제 커버리지 리포트를 뽑고, 각 도구가 계측하는 단위(instruction·statement·branch·arc)의 차이를 설명할 수 있다
- 단위·통합·E2E 테스트의 커버리지를 병합하고, 변경분(diff) 커버리지를 계산해 CI 게이트로 걸 수 있다
- 제어 흐름 그래프에서 실현 불가능 경로를 걸러내고, 루프 경계 기준으로 경로 집합을 줄일 수 있다
- 변수의 정의-사용(DU) 쌍을 표로 뽑고, all-defs·all-uses·all-du-paths 커버리지 기준으로 테스트 케이스를 설계할 수 있다
dd·ur·dk같은 데이터 흐름 이상을 코드에서 찾아내고, 정적 분석 경고와 연결해 설명할 수 있다- PIT·Stryker로 뮤테이션 테스트를 돌리고, 생존 뮤턴트를 "어설션 부족·케이스 부족·등가 뮤턴트·죽은 코드"로 분류할 수 있다
- ASan·LSan·Valgrind로 메모리 누수와 use-after-free를 재현하고, 리포트의 스택 트레이스와 누수 분류를 읽을 수 있다
- SAST 경고를 오탐·진탐·수용으로 트리아지하고, 베이스라인과 "새 위반 0" 게이트로 운영할 수 있다
- 코드 리뷰를 체크리스트·결함 유형 분류·리뷰 지표가 있는 테스트 활동으로 설계하고, 리뷰 결과를 테스트 설계에 환류할 수 있다
채용시장에서의 위치
국내 공고에서 이 모듈의 내용은 보통 "화이트박스 테스트", "코드 커버리지 관리", "정적 분석 도구 운영", "품질 게이트 구축" 같은 문구로 나타난다. 자동차·의료기기·항공처럼 기능안전 규격을 받는 조직에서는 아예 필수 요건이다 — ISO 26262·IEC 62304·DO-178C는 구조 커버리지 달성과 정적 분석 결과 처리를 증거로 요구하기 때문이다(모듈 35, 모듈 40). 일반 웹·앱 조직에서도 SonarQube 같은 도구를 "누가 운영하고 경고를 누가 판정하는가"는 대개 비어 있는 자리이고, QA가 그 자리를 가져가면 역할이 뚜렷해진다.
면접에서 가장 약한 답은 "커버리지 80%를 목표로 관리했습니다"이다. 이 답은 숫자를 관리했다는 말이지 품질을 관리했다는 말이 아니다. 강한 답은 "전체 커버리지 대신 변경분 커버리지로 게이트를 바꿔 신규 코드의 미검증 비율을 추적했다", "결제 모듈에만 뮤테이션 테스트를 걸었더니 커버리지 91%인 구간에서 뮤테이션 점수가 43%로 나와 어설션이 없는 테스트 27개를 찾아냈다", "SAST 경고 1,400건을 베이스라인으로 묶고 신규 위반 0 게이트만 남겨 리뷰 부담을 없앴다" 처럼 숫자의 성격을 바꾼 경험이다.
역할 이름으로는 SDET·QA 엔지니어·품질 엔지니어(Quality Engineer)와 겹치고, 개발 조직 안에서 테스트를 담당하는 자리일수록 비중이 커진다. ISTQB 체계에서는 CTAL-TTA(Technical Test Analyst)가 구조 기반 기법·정적 분석·동적 분석을 정면으로 다루므로, 이 모듈을 마치면 그 시험의 해당 장을 실습 경험과 함께 설명할 수 있다.
레슨 (5개)
- 고급약 40분
커버리지 도구 실습 — JaCoCo·Istanbul·coverage.py로 리포트를 뽑고 CI 게이트까지
커버리지 개념은 모듈 3과 모듈 10에서 배웠다. 여기서는 도구를 직접 돌린다. JaCoCo는 바이트코드를, Istanbul은 변환된 소스를, coverage.py는 실행 추적을 계측한다는 차이가 리포트 숫자를 어떻게 바꾸는지 확인하고, 단위·통합·E2E 커버리지를 병합하고, 전체 커버리지 대신 변경분 커버리지로 CI 게이트를 거는 법까지 실습한다.
- 고급약 40분
경로 테스트와 데이터 흐름 테스트 — 실현 불가능 경로를 걸러내고 정의-사용 쌍으로 설계한다
기저 경로를 뽑는 절차는 모듈 3에서 배웠다. 여기서는 실제 코드에서 부딪히는 문제를 다룬다. 실현 불가능 경로를 걸러내고 루프를 유한한 케이스로 줄이는 법, 그리고 제어 흐름만으로는 보이지 않는 결함을 잡는 데이터 흐름 테스트 — 변수의 정의-사용(DU) 쌍을 뽑아 all-defs·all-uses·all-du-paths 기준으로 케이스를 설계하고, dd·ur·dk 같은 데이터 흐름 이상을 찾아내는 법을 익힌다.
- 고급약 40분
뮤테이션 테스트 — 커버리지가 답하지 못하는 질문, 이 테스트는 결함을 잡는가
커버리지는 코드가 실행됐는지만 센다. 뮤테이션 테스트는 코드에 의도적으로 결함을 심고 테스트가 실패하는지 확인해 테스트의 검출력을 직접 측정한다. PIT와 Stryker를 실제로 돌리고, 뮤테이션 점수를 읽고, 생존 뮤턴트를 어설션 부족·케이스 부족·등가 뮤턴트·죽은 코드로 분류하며, 느린 실행 시간을 변경분 한정 실행으로 실무에서 감당 가능하게 만드는 법을 익힌다.
- 고급약 45분
정적·동적 분석 심화 — 메모리 누수·자원 릭·와일드 포인터를 도구로 잡아낸다
테스트가 초록색인데도 남아 있는 결함을 다룬다. 정적 분석이 잡는 것과 원리상 못 잡는 것을 가르고, 오탐을 억제 규칙과 신규 코드 게이트로 운영하는 방식을 익히고, ASan·LSan·UBSan·TSan과 Valgrind 계열이 각각 무엇을 검출하며 성능 대가가 얼마인지 실제 출력으로 확인한다. 관리 언어의 누수 형태와 CI 배치 전략까지 다룬다.
- 고급약 40분
코드 리뷰를 테스트 활동으로 운영하기 — 체크리스트와 결함 유형 분류
코드 리뷰를 결함이 기록되고 유형이 집계되는 정적 테스트 활동으로 옮긴다. 결함 이력에서 체크리스트를 뽑는 절차, 역할별 분담, 리뷰 결과를 다음 체크리스트로 되먹이는 순환, 세면 안 되는 리뷰 지표, QA가 코드를 다 읽지 않고도 값을 만드는 네 개입 지점을 다룬다.
이 모듈의 실습
실습은 별도 저장소에서 진행합니다. 새 탭으로 열립니다.
- 커버리지 리포트 읽기와 뮤테이션으로 약한 테스트 찾기고급 · 약 100분 · 바로 실습
도구: vitest, istanbul