← doubleon study hub

A Field Guide to the Canon · 정독본

소프트웨어 테스트를 관통하는 것들

좋은 테스트란 결국 “두려움 없이 코드를 바꾸게 해주는 것” — 변경에 대한 자신감을 파는 자산이다. 자동화 테스트의 거의 모든 기법은 그 자신감을 키우거나, 그 자신감을 갉는 적을 없애는 일이다. 그 핵심 20%를 한 번에 훑는다.

분량약 2시간 정독 구성8개 장 · 10개 도해 범위개발자 관점 자동화 테스트 이후장별 원전으로 드릴다운
00 · 시작하며 · 8분

테스트는 왜 쓰는가 — 진짜 목적

테스트를 공부하려고 자료를 펼치면 기법의 홍수에 빠진다. TDD, BDD, 테스트 더블, 피라미드, 트로피, 커버리지, 변이 테스트, 속성 기반 테스트, 계약 테스트… 서로 다른 이름들이 각자 옳다고 말한다. 하지만 이것들을 나란히 놓으면 하나의 질문으로 수렴한다: 이 테스트가 정말 나를 도와주는가?

테스트의 목적은 “버그를 잡는 것”이 아니다. 그건 부산물이다. 진짜 목적은 변경에 대한 자신감이다 — 코드를 바꾸고 배포 버튼을 누를 때 “안 깨졌다”를 두려움 없이 믿을 수 있는 상태. 이 렌즈로 보면 모든 기법이 두 부류로 갈린다: 자신감을 키우는 것(회귀를 잡고, 설계를 이끌고, 신뢰도를 측정), 그리고 자신감을 갉는 적을 없애는 것(취약함·비결정성 제거).

이 자료를 관통하는 한 문장

테스트 스위트는 “변경에 대한 자신감”을 파는 자산이다. 신뢰할 수 없는 테스트는 자산이 아니라 부채다. 모든 기법은 이 자신감을 높이거나, 그것을 갉는 적을 없애는 일이다.

그렇다면 “좋은 테스트”란 무엇인가? Vladimir Khorikov는 좋은 테스트를 떠받치는 네 기둥을 제시한다. 이 넷이 이 자료 전체의 채점 기준이다.

변경에 대한 자신감 회귀보호 리팩터링내성 빠른피드백 유지보수성 네 기둥은 서로 상충한다 — 하나를 키우면 다른 하나가 눌린다 그래서 “균형”이 곧 설계다
FIG. 1Khorikov의 네 기둥 — 회귀 보호 · 리팩터링 내성 · 빠른 피드백 · 유지보수성. 넷은 동시에 최대가 될 수 없다(예: E2E는 회귀 보호가 강하지만 피드백이 느리다). 좋은 테스트 설계란 이 네 축의 균형점을 고르는 일이다. Kent Beck의 “Test Desiderata”(isolated·fast·deterministic·readable·behavioral…)도 같은 결의 목록이다.

이후 8개 장은 이 자신감을 따라 흐른다. 테스트로 설계를 이끌고(TDD·BDD) → 무엇을 얼마나 테스트할지 층위를 잡고(피라미드·트로피) → 빠르고 안정된 테스트를 위해 격리하고(더블·테스트 가능성) → 스위트를 얼마나 신뢰할지 측정하고(커버리지·변이·속성) → 그 신뢰를 갉는 적을 제거한다(flaky·냄새).

한 줄 요약테스트의 목적은 버그가 아니라 변경에 대한 자신감. 좋은 테스트 = 회귀보호·리팩터링내성·빠른피드백·유지보수성의 균형.
01 · 방법 · 20분

테스트가 설계를 이끈다

테스트를 “다 만든 뒤 검증하는 절차”로 생각하면 절반만 본 것이다. 정전들의 공통된 통찰은 더 급진적이다: 테스트를 먼저 쓰면, 그것이 설계를 이끈다. 쓰기 어려운 테스트는 곧 나쁜 설계의 신호이기 때문이다.

Kent Beck · TDD By Example
TDD — Red · Green · Refactor

테스트 주도 개발(TDD)은 구현보다 먼저 테스트를 쓰고, 그 실패하는 테스트를 통과시키는 최소한의 코드를 쓴 뒤 정리하는 개발법이다. Kent Beck의 *Test-Driven Development: By Example*이 원전이며, 사이클은 세 박자로 돈다.

RED 실패하는 테스트 GREEN 통과 최소 코드 REFACTOR 설계 개선 ① 원하는 동작을 명세 ② 안전망 확보 ③ 다음 작은 스텝
FIG. 2Red 실패하는 작은 테스트를 먼저 쓰고 → Green 통과시키는 가장 단순한 코드를 쓴 뒤 → Refactor 테스트라는 안전망 아래 설계를 다듬는다. 작은 스텝·빠른 피드백으로 “두려움을 지루함으로 바꾼다”(Beck).

여기서 핵심은 두 가지다. 첫째, 테스트는 검증 도구이자 설계 도구다. 테스트가 쓰기 고통스럽다면 그 코드의 결합이 너무 강하다는 뜻이고, 이는 3장의 테스트 가능성으로 이어진다. 둘째, TDD엔 두 학파가 있다.

  • classicist / Detroit 학파 — 실제 객체를 쓰고 결과 상태를 검증한다. 리팩터링에 강하다.
  • mockist / London 학파 — 협력 객체를 mock으로 대체하고 상호작용을 검증하며, 바깥에서 안으로(outside-in) 설계를 유도한다.

Ian Cooper의 강연 “TDD, Where Did It All Go Wrong”은 이 논쟁을 한 문장으로 정리한다 — “구현 세부가 아니라 동작(behavior)을 테스트하라.” 테스트의 단위는 클래스나 메서드가 아니라 관찰 가능한 동작이어야 리팩터링에도 살아남는다.

균형 · TDD도 만능은 아니다

건강한 반론도 정전의 일부다. DHH는 “Is TDD Dead?” 대담에서 test-induced design damage(테스트를 위해 설계가 뒤틀리는 현상)를 지적했고, James Coplien의 “Why Most Unit Testing Is Waste”는 mock 과용·의미 없는 유닛 테스트를 비판한다. TDD의 교훈은 “항상 테스트를 먼저”가 아니라 “테스트하기 쉽게 설계하고, 동작을 테스트하라”에 가깝다.

Dan North · Introducing BDD
BDD — 동작을 비즈니스 언어로

TDD를 하다 보면 “다음에 뭘 테스트하지?”, “test라는 단어가 주는 오해”에 부딪힌다. Dan North의 행위 주도 개발(BDD)은 이를 동작(behavior)이라는 말로 다시 세운다. 시스템이 “무엇을 해야 하는가”를 개발자·QA·비즈니스가 공유하는 언어(ubiquitous language)로 서술하는 것이다.

형식은 Given-When-Then: “주어진 상황에서 · 어떤 사건이 일어나면 · 이런 결과가 나온다.” 이 시나리오는 요구사항이자 곧 실행 가능한 테스트가 된다(Cucumber/Gherkin 등). 명세가 항상 최신 검증 상태를 반영하는 살아있는 문서(living documentation)가 되는 것이 핵심 이점이다.

Gojko Adzic · Bill Wake
예시로 명세하고, AAA로 구조화한다

BDD와 짝을 이루는 것이 Gojko Adzic의 예시 기반 명세(Specification by Example)다. 추상적 요구 대신 구체적 핵심 예시(key examples)를 협업으로 도출하고, 그 예시를 자동화된 명세로 만든다. “무엇을 만들지”에 대한 공유된 이해가 그대로 회귀 스위트가 된다.

테스트 한 개의 내부 구조에도 정전적 형태가 있다 — Arrange-Act-Assert(AAA). Bill Wake가 대중화한 이 패턴은 테스트 본문을 세 구간으로 나눠 의도를 한눈에 읽히게 한다. BDD의 Given-When-Then과 정확히 동형(isomorphic)이다.

유닛 테스트 · AAA BDD · GIVEN-WHEN-THEN Arrange대상·의존성·입력 준비 Given전제 상태 Act단 하나의 동작 실행 When사건 발생 Assert관찰 가능한 결과 확인 Then기대 결과
FIG. 3같은 뼈대, 두 언어. AAA(유닛)와 Given-When-Then(BDD)은 준비→사건→기대의 동형 구조다. Meszaros의 4단계(Setup-Exercise-Verify-Teardown)와도 대응한다. 한 테스트 = 한 동작 = 한 개념의 단언으로 유지하면 “Assertion Roulette”(어느 단언이 실패했는지 모호) 냄새를 피한다.
한 줄 요약테스트를 먼저 쓰면(TDD) 설계가 좋아지고, 동작을 비즈니스 언어로 쓰면(BDD·SbE) 명세가 곧 테스트가 된다. 핵심은 “구현이 아니라 동작을 테스트하라”.
02 · 전략 · 18분

무엇을·얼마나 테스트하나

테스트는 공짜가 아니다. 느린 테스트는 자주 못 돌리고, 취약한 테스트는 신뢰를 갉는다. 그래서 어느 층위에 얼마나 투자할지가 전략의 핵심이다. 정전들은 이를 모양으로 이야기한다.

Cohn · Fowler · Google
테스트 피라미드 — 아래로 많이, 위로 적게

테스트 피라미드는 Mike Cohn의 *Succeeding with Agile*에서 나와 Martin Fowler가 대중화한 은유다. 아래로 갈수록 많고 빠르고 싸게, 위로 갈수록 적게.

  • 바닥 · 유닛 테스트 — 많고 빠르고 결정적. 로직의 세부를 촘촘히. (‘단위’를 하나만 격리하면 solitary, 실제 협력자와 함께 검증하면 sociable 유닛 테스트.)
  • 중간 · 통합/서비스/계약 테스트 — 컴포넌트 경계와 연동을 검증.
  • 꼭대기 · UI / E2E — 적게. 느리고 깨지기 쉽다.

이 모양의 논리는 단순하다. 상위 테스트는 느리고 불안정하며 실패해도 원인을 찾기 어렵다(Google의 “Just Say No to More End-to-End Tests”). 각 층은 중복이 아니라 역할 분담이다. 이를 뒤집은 형태 — UI·수동 테스트가 위로 뚱뚱한 — 가 악명 높은 안티패턴 “아이스크림 콘”이다.

E2E 통합 유닛(최대) 피라미드 ✓ E2E 통합(최대) 트로피 정적분석·유닛·통합·E2E 수동/E2E 통합 유닛(최소) 아이스크림 콘 ✕
FIG. 4같은 재료, 다른 분배. 피라미드는 유닛을 가장 넓게. 트로피(Dodds)는 통합을 가장 넓게. 아이스크림 콘은 느리고 취약한 상위 테스트가 뚱뚱한 안티패턴 — 스위트가 느려지고 자주 깨진다.

Kent C. Dodds
테스팅 트로피 — 통합에 무게를

프론트엔드 맥락에서 Kent C. Dodds는 테스팅 트로피를 제안했다. 표어 “Write tests. Not too many. Mostly integration.”(Guillermo Rauch의 말을 Dodds가 대중화)를 걸고, 정적분석(타입·린트)을 최하층에 두고 렌더링·상호작용을 함께 검증하는 통합 테스트에 가장 큰 무게를 둔다. 근거는 이 한 문장에 있다.

“The more your tests resemble the way your software is used, the more confidence they give you.”

— Kent C. Dodds, The Testing Trophy

피라미드와 트로피는 대립이 아니다. 근본 취지(느리고 취약한 E2E를 최소화)는 같고, 강조점만 시스템 특성에 따라 이동한 것이다. 백엔드·도메인 로직이 두꺼우면 피라미드가, UI 통합 신뢰가 중요한 프론트엔드면 트로피가 더 맞는다. 모양은 목적이 아니라 맥락의 함수다.

Robinson & Fowler · Pact
중간층을 지키는 법 — 소비자 주도 계약 테스트

마이크로서비스에선 “서비스 A가 바뀌면 B가 깨지지 않을까?”가 늘 문제다. 이를 느리고 취약한 E2E로 확인하는 대신, 소비자 주도 계약 테스트(Consumer-Driven Contract Testing)소비자가 실제로 기대하는 상호작용을 계약으로 명시하고 제공자가 그 계약을 만족하는지 검증한다(Pact 등). 소비자는 제공자를 테스트 더블로 세워 계약을 만들고, 제공자는 그 계약을 재생해 확인한다. 피라미드 중간층을 튼튼하게 만드는 핵심 도구다.

한 줄 요약아래로 많이·위로 적게(피라미드), 프론트는 통합 중심(트로피), 아이스크림 콘은 피한다. 서비스 간은 E2E 대신 계약 테스트로.
03 · 격리 · 18분

격리의 기술 — 더블과 테스트 가능성

빠르고 결정적인 테스트를 쓰려면 대상을 그 협력자(데이터베이스·네트워크·시간)로부터 격리해야 한다. 이 장은 격리의 두 얼굴을 다룬다: 협력자를 대체하는 도구(테스트 더블)와, 애초에 대체가 쉽도록 만드는 설계(테스트 가능성).

Meszaros · Fowler · Searls
테스트 더블 — 다섯 종류의 대역

테스트 더블(Test Double)은 실제 협력 객체를 대신하는 대역의 총칭이다(영화의 스턴트 더블에서 온 말). Gerard Meszaros가 *xUnit Test Patterns*에서 다섯 종류로 표준화했다.

테스트 대상 (SUT) system under test 협력 객체 자리 실제 대신 더블을 끼움 Dummy 자리만 채움 안 쓰임 Stub 정해둔 값 반환 상태 기반 Spy 호출을 기록 나중에 확인 Mock 기대 상호작용 검증 행위 기반 Fake 경량 구현 인메모리 DB
FIG. 5다섯 대역. Dummy(자리 채우기) · Stub(값 반환, 상태 기반) · Spy(호출 기록) · Mock(기대 상호작용 검증, 행위 기반) · Fake(동작하는 경량 구현). 흔히 다 “목”이라 부르지만 역할이 다르다.

여기서 2장의 TDD 학파가 다시 등장한다(Fowler의 “Mocks Aren’t Stubs”). classicist는 결과 상태를 확인하며 stub·fake를 선호하고, mockist상호작용을 mock으로 확인한다. 무엇을 고르든 원칙은 하나다.

주의 · mock은 남용하기 쉬운 도구다

소유한 인터페이스만 mock하라(서드파티 라이브러리를 직접 mock 금지 — Justin Searls “Please Don’t Mock Me”). 구현 세부를 mock으로 고정하면 리팩터링만 해도 테스트가 깨진다(리팩터링 내성 붕괴). 그리고 mock이 자꾸 많아진다면, 그건 대개 설계가 강결합이라는 신호다 — 다음 절로 이어진다.

Feathers · Hevery
테스트 가능성 — 좋은 설계와 같은 방향

테스트하기 어렵다는 건 대개 테스트의 문제가 아니라 설계의 문제다. Michael Feathers의 표현대로 테스트 가능성과 좋은 설계는 같은 방향을 가리킨다(“The Deep Synergy Between Testability and Good Design”). Miško Hevery는 테스트를 어렵게 만드는 전형을 짚는다:

  • 생성자에서 일하기 — new로 협력자를 직접 만들어 버리면 대체할 수 없다.
  • 전역/정적 상태·싱글턴 남용 — 숨은 결합.
  • 암묵적 부수효과(숨은 의존성) — 시간·랜덤·네트워크에 몰래 의존.
✕ 강결합 · 협력자를 내부에서 생성 주문서비스 new 결제() 테스트가 실제 결제 서버를 호출 → 느리고 위험 ✓ 의존성 주입 · 이음새(seam) 주문서비스 결제: 결제I 주입: Test Double ← 여기서 대체 가능
FIG. 6왼쪽은 협력자를 내부에서 new 해버려 대체가 불가능하다. 오른쪽은 인터페이스로 받아 주입하므로 테스트에서 더블을 끼울 이음새(seam)가 생긴다 — 의존성 주입, 함수형 코어/명령형 셸, 시간·랜덤의 추상화가 모두 이 이음새를 만드는 기법이다.

처방은 의존성 주입(DI), 부수효과를 경계로 밀기(함수형 코어 / 명령형 셸), 시간·랜덤·네트워크의 추상화다. 이는 아키텍처의 정보 은닉·의존성 규칙과 정확히 같은 방향이다. 레거시 코드라면 Michael Feathers의 이음새(seam)를 찾아 테스트를 주입한다(*Working Effectively with Legacy Code*). UI 층에서는 화면을 객체로 캡슐화하는 페이지 객체(Page Object)가 같은 역할을 한다 — 셀렉터 같은 세부를 감춰, UI가 바뀌어도 한 곳만 고치면 되게 한다(Fowler).

한 줄 요약협력자는 다섯 더블로 대체하되 mock은 아껴 쓴다. 대체가 어렵다면 설계를 고쳐라 — 테스트 가능성 = 좋은 설계.
04 · 신뢰 측정 · 20분

테스트를 어떻게 신뢰하나

테스트를 많이 썼다고 안심할 수 있을까? “테스트가 있다”와 “테스트를 믿을 수 있다”는 다르다. 이 장은 스위트의 진짜 실력을 재는 세 가지 렌즈다 — 커버리지(무엇을 실행했나), 변이(정말 결함을 잡나), 속성(사람이 놓친 입력까지 잡나).

Ammann & Offutt · Marick · Fowler
커버리지 — 목표가 아니라 도구

테스트 커버리지는 테스트가 코드나 입력 공간의 어느 부분을 실행했는지를 재는 척도다. Ammann & Offutt는 기준을 체계화한다: 구문(statement)·분기(branch)·경로(path), 논리(condition·MC/DC), 입력공간(동등분할·경계값·pairwise). 하지만 정전들의 공통 경고가 있다.

경고 · 높은 커버리지 ≠ 좋은 테스트

단언(assert) 없이 코드를 실행만 해도 커버리지는 오른다(Marick “How to Misuse Code Coverage”). 그래서 커버리지 목표치(예: 100%)를 강제하면 의미 없는 테스트만 양산된다(Fowler “Test Coverage”). 커버리지의 진짜 용도는 테스트가 비어 있는 위험 지점을 찾는 것이지, 품질을 증명하는 숫자가 아니다.

Jia & Harman
변이 테스트 — 테스트를 테스트하기

커버리지가 “실행했는가”만 본다면, 변이 테스트(Mutation Testing)는 “결함이 있으면 정말 실패하는가”를 본다. 코드에 인위적 결함(mutant)을 심고, 스위트가 그것을 잡아내는지로 테스트의 실제 품질을 측정한다.

① 원본 코드에 변이를 심는다 if (x > 0) { … } > → >= 로 변이 if (x >= 0) { … } ← mutant ② 스위트를 돌린다 테스트 실패 → killed ✓ 단언이 결함을 잡았다 = 좋은 테스트 테스트 통과 → survived ✕ 결함이 있는데 안 잡힘 = 테스트 공백 Mutation score = killed / 전체 살아남은 변이 = 채워야 할 곳
FIG. 7변이체에 스위트를 돌려 killed(실패=좋음)인지 survived(통과=공백)인지 본다. 커버리지 100%라도 단언이 부실하면 변이가 살아남는다. 한계: 계산 비용이 크고, 의미가 같아 죽일 수 없는 equivalent mutant 판별이 어렵다. 도구: PIT·Stryker 등.

Claessen & Hughes · QuickCheck
속성 기반 테스트 — 예시를 넘어서

사람이 쓰는 예시 테스트는 사람이 상상한 입력만 검사한다. 속성 기반 테스트(Property-Based Testing)는 구체적 예시 대신 항상 성립해야 하는 속성을 명시하고, 도구가 무작위 입력을 대량 생성해 반례를 찾는다. Claessen & Hughes의 QuickCheck 논문이 원전이다.

속성 정의 rev(rev x)=x 무작위 입력 대량 하나가 반례 반례 발견 shrinking 최소 반례 디버깅 쉬움
FIG. 8속성(예: reverse(reverse(xs))==xs, 왕복 인코딩, 불변식)을 정의하면 도구가 무작위 입력으로 반례를 찾고, shrinking으로 반례를 최소 형태까지 줄여 준다. 예시 테스트를 보완하지 대체하지 않는다. 무작위/변형 입력으로 크래시를 찾는 퍼징(fuzzing)도 같은 계열이다.
한 줄 요약커버리지는 “공백 찾기” 도구일 뿐(목표 아님), 변이 테스트는 단언의 유효성을, 속성 기반은 사람이 놓친 입력을 잡는다.
05 · 적 · 14분

신뢰를 갉는 적 — Flaky와 테스트 냄새

아무리 잘 설계한 스위트도 신뢰를 잃으면 자산에서 부채로 바뀐다. 신뢰를 갉는 두 적이 있다: 비결정적으로 깜빡이는 flaky 테스트와, 유지보수를 좀먹는 테스트 냄새.

Luo 외 · Fowler · Google
Flaky Test — 빨간 불을 무시하게 만드는 병

Flaky 테스트는 코드 변경이 없는데도 같은 테스트가 통과·실패를 오가는 비결정적 테스트다. 가장 무서운 점은 2차 피해다 — 한 번 “가끔 빨개지는 테스트”가 생기면 팀은 빨간 불을 무시하기 시작하고, 그러면 진짜 회귀도 함께 묻힌다. 스위트 전체의 신뢰가 무너진다.

같은 테스트 · 코드 변경 없음 → 신뢰 붕괴 대응 흐름 (방치 금지) flaky 감지 격리(quarantine) 원인 수정시간·랜덤·순서·동시성 복귀
FIG. 9주요 원인(Luo 외 실증 연구): 비동기 대기(고정 sleep)·테스트 순서/격리 실패·동시성 경쟁·외부 의존(네트워크·시간). 대응(Fowler “Eradicating Non-Determinism”): 감지 즉시 격리 후 반드시 고친다 — 시간·랜덤·네트워크를 더블로 제어하고, 고정 sleep 대신 조건 기반 대기를. Google도 flaky를 시스템적으로 추적·격리한다.

Meszaros · xUnit Test Patterns
테스트 냄새 — 테스트도 1급 코드다

테스트 코드도 유지보수 대상이다. Gerard Meszaros는 테스트의 신뢰·유지보수를 해치는 반복적 징후를 테스트 냄새로 카탈로그화했다. 대부분의 냄새는 결국 프로덕션 코드의 설계 문제(테스트 가능성)를 비추는 거울이다.

Smell

Fragile Test

구현 세부만 바꿔도 깨진다. 과한 mock·구현 결합 → 리팩터링 내성 상실.

Smell

Obscure Test

의도가 안 읽힌다. setup 과다·AAA 붕괴. 테스트가 문서 역할을 못 함.

Smell

Assertion Roulette

단언이 뭉쳐 어느 게 실패했는지 모호. 한 테스트=한 개념으로.

Smell

Slow Test

느려서 자주 못 돌린다 → 피드백 붕괴. 외부 의존을 격리.

Smell

Mystery Guest

테스트 밖의 파일·DB에 몰래 의존. 재현·이해가 어렵다.

Smell

Test Duplication

준비 코드 중복. 헬퍼·빌더로 의도만 남긴다.

한 줄 요약flaky는 감지 즉시 격리·수정(방치가 최악), 테스트 냄새는 1급 코드로서의 가독성·독립성으로 다스린다. 둘 다 신뢰를 지키는 일.
06 · 종합 · 6분

하나의 지도로 묶기

16개 개념을 지나왔다. 처음의 목적으로 돌아가 전체를 접으면, 모든 것은 “변경에 대한 자신감을 파는 자산”이라는 중심 아래 다섯 갈래다.

The one purpose
테스트 = 변경에 대한 자신감을 파는 자산

① 테스트가 설계를 이끈다

먼저 쓰고, 동작으로 명세한다.

TDDBDD예시 기반 명세AAA

② 무엇을·얼마나

어느 층위에 얼마나 투자하나.

테스트 피라미드테스팅 트로피유닛 테스트계약 테스트

③ 격리의 기술

협력자를 끊어 빠르고 안정되게.

테스트 더블테스트 가능성페이지 객체

④ 신뢰를 측정

스위트의 진짜 실력을 잰다.

커버리지변이 테스트속성 기반

⑤ 신뢰를 갉는 적

자산을 부채로 만드는 것들.

Flaky Test테스트 냄새

이 지도의 화살표들은 서로를 가리킨다. TDD(①)로 먼저 쓰면 설계가 좋아지고(③ 테스트 가능성), 그래서 협력자를 더블(③)로 끊어 빠른 유닛 테스트(②)를 만든다. 그 스위트를 얼마나 믿을지는 커버리지·변이(④)로 재고, flaky·냄새(⑤)가 그 신뢰를 갉으면 즉시 고친다. 그리고 층위(②)를 잘못 뒤집으면(아이스크림 콘) 전체가 느려져 자신감이 무너진다. 모든 실은 “자신감”이라는 한 매듭으로 이어진다.

한 문장으로 다시

좋은 테스트란 동작을 명세해 설계를 이끌고, 층위를 맞게 배치하고, 격리로 빠르고 안정되게 만들며, 신뢰를 측정하고 그 신뢰를 지키는 것이다 — 그 모든 목적은 두려움 없는 변경, 즉 자신감이다.

07 · 다음 걸음 · 6분

더 깊이 — 먼저 읽어야 할 세 원전

이 자료는 지형을 훑는 지도였다. 50여 편의 정전 중 딱 세 개만 먼저 읽는다면 이 순서를 권한다 — 나머지 개념 대부분이 여기서 갈라져 나온다.

01
Test-Driven Development: By ExampleKent Beck · 단행본

TDD의 원전. Red-Green-Refactor를 실제 예제로 몸에 새긴다. “테스트는 설계 도구”라는 이 분야의 출발점. — 1장의 뿌리.

02
Unit Testing: Principles, Practices, and PatternsVladimir Khorikov · 단행본

좋은 테스트의 네 기둥, classicist vs mockist, “구현이 아니라 동작을 테스트하라”를 가장 명료하게 정리한 현대 표준서. — 0·1·3장의 뼈대.

03
Test Pyramid / The Practical Test PyramidFowler · Ham Vocke · 아티클

층위 전략을 짧고 정확하게. 이어서 Dodds의 “Testing Trophy”와 Google의 “Just Say No to More E2E Tests”를 함께 읽으면 2장이 완성된다.

이 셋을 소화한 뒤엔 관심 갈래로 넓히면 된다: 더블·설계가 궁금하면 Meszaros xUnit Test Patterns와 Fowler “Mocks Aren’t Stubs”, 레거시라면 Feathers Working Effectively with Legacy Code로. 측정이 궁금하면 Ammann & Offutt Introduction to Software Testing과 Hughes QuickCheck로. 대규모 실전은 Software Engineering at Google의 테스트 장으로.

읽기와 정리를 함께

새 자료를 읽을 때마다 흩어진 메모로 남기지 말고 개념 단위로 누적하자. 각 원전이 이 지도의 어느 갈래에 속하는지 이미 보이니, 새로 읽은 사실을 그 개념 위에 덧붙이면 지식이 복리로 쌓인다.