소프트웨어 테스트의 계보 — 디버깅에서 AI 시대까지, 「올바름」을 묻는 70년
1940년대 「첫 번째 버그」 일화에서 시작해, xUnit의 탄생, TDD/BDD의 융성, 목과 속성 기반 테스트, E2E의 세대교체, 커버리지와 뮤테이션, 플레이키 테스트와의 싸움, 그리고 생성형 AI가 테스트 작성법을 바꾸고 있는 현재까지. 「프로그램이 올바른지 어떻게 확인하는가」 「테스트로 무엇을 보장할 수 있고, 무엇을 보장할 수 없는가」라는 물음이 시대마다 어떻게 다시 만들어져 왔는가를 따라가는, 전 18화 시리즈 지도.
소프트웨어 테스트에 「역사」는 있는가
있다. 그것도 70여 년의. 그리고 중요한 것은, 소프트웨어 테스트는 하나의 「올바른 방법」이 아니라 시대마다 근본부터 다시 만들어져 왔다는 것이다. 1960년대 프로그래머가 생각한 「테스트」와, 2000년대 TDD 실천자가 생각한 「테스트」와, 2020년대에 AI와 짝을 이루는 개발자가 생각하는 「테스트」는 전제 자체가 다르다.
본 시리즈는 자매 시리즈 [수학의 계보]·[음악 이론의 계보]가 「물음과 답의 변천」으로 학문의 역사를 따라간 것과 같이, 소프트웨어 테스트를 사고방식의 역사로 따라간다. 중심에 있는 물음은 단순하지만, 지금도 결판나지 않았다.
프로그램이 올바르다는 것을, 어떻게 확인하는가. 그리고 테스트는 무엇을 보장할 수 있고, 무엇을 보장할 수 없는가.
이 두 물음에 대한 답은 수작업 디버깅에서 자동화된 프레임워크로, 나아가 생성형 AI로, 70년에 걸쳐 몇 번이고 다시 쓰여 왔다. 본 시리즈는 그 다시 쓰기의 역사를 따라간다.
관통하는 4개의 실
70년을 관통하는 대립·과제가 4개 있다. 어느 시대의 이야기든 이 4개 중 하나에 닿아 있다.
- 검증 vs 타당성 확인 — 「명세대로 올바르게 만들었는가(Verification)」와 「애초에 올바른 것을 만들고 있는가(Validation)」. 테스트는 거의 검증의 영역에 머물러 왔고, 타당성 확인은 계속 별개의 문제로 남아 있다
- 수동에서 자동화로, 그리고 AI로 — 누가, 무엇이 테스트를 쓰고 실행하는가. 수작업 카드 대조에서 xUnit 프레임워크로, CI 상의 자동 실행으로, 나아가 AI에 의한 초안 생성으로, 주체 자체가 옮겨 왔다
- 어디서 확인하는가 — 단위·통합·E2E 중 어디에 비중을 둘 것인가. 테스트 피라미드·트로피·허니콤, 그리고 아이스크림 콘(안티패턴)이라는 전략 모델의 대립
- 완전성의 한계 — 데이크스트라의 경구 「테스트는 버그의 존재를 보여줄 수 있지만, 부재는 보여줄 수 없다」가 들이민 원리적 한계. 형식 기법은 이 한계를 수학적으로 메우려는 또 하나의 길이다
한 줄로 되짚는 70년
먼저 연표를 한눈에 훑어 두자. 세부는 각 화에 맡기고, 여기서는 「시대마다 무슨 일이 있었는가」를 한 줄로 짚어 둔다.
| 시대 | 한마디로 |
|---|---|
| ~1970년대 | 수동 확인과 디버깅의 연장. 테스트는 아직 독립된 공정이 아니었다 |
| 1990년대 중반 | SUnit이 xUnit 계열의 원형 패턴(픽스처·테스트 러너 등)을 확립한다 |
| 1997~2002년 | JUnit의 보급과 TDD의 체계화로, 테스트가 「설계를 이끄는 행위」가 된다 |
| 2000년대 후반 | BDD·Cucumber·『xUnit Test Patterns』로 테스트의 어휘와 기법이 결정화된다 |
| 2010년대 전반 | 프런트엔드용 프레임워크(Jasmine → Jest)가 폭발적으로 보급된다 |
| 2010년대 후반 | Selenium 독주 체제에서 Cypress·Puppeteer로, E2E 도구의 세대교체가 진행된다 |
| 2020년대 | Playwright에 의한 멀티 브라우저 통일과, LLM에 의한 테스트 생성이 확산된다 |
70년의 5개 시대 — 전 18화 지도
이하, 전 18화(overview 제외)를 5개의 Part로 나누어 소개한다.
Part I: 전사와 자동화의 여명(제1~3화)
아직 「테스트」가 독립된 공정이 아니었던 시대부터, xUnit이라는 공통 언어가 세계로 퍼져 나가기까지를 따라간다.
| 화 | 제목 | 내용 |
|---|---|---|
| 제1화 | 전사 — 디버깅에서 테스트로 | 디버깅과 테스트가 미분화되어 있던 1950년대, 소프트웨어 위기, 데이크스트라의 경구, 마이어스 『The Art of Software Testing』(1979) |
| 제2화 | xUnit의 탄생 | 켄트 벡의 SUnit(Smalltalk), 비행기 안에서 쓰였다는 JUnit의 일화, TestCase·assert·fixture라는 공통 어휘의 확립 |
| 제3화 | xUnit의 세계 확산 | JUnit의 설계 사상이 C++·.NET·Python·Ruby·PHP 등 각 언어로 이식되어 가는 과정 |
Part II: 사상의 융성(제4~7화)
테스트가 「버그 찾기」에서 「설계를 이끄는 행위」로 의미를 바꾸어 간, 사상적 전환의 시대.
| 화 | 제목 | 내용 |
|---|---|---|
| 제4화 | TDD의 융성과 논쟁 | 켄트 벡 『Test-Driven Development: By Example』(2002), Red-Green-Refactor, 「TDD is dead」 논쟁 |
| 제5화 | BDD로 | 댄 노스가 제창한 BDD, Gherkin과 Cucumber, 「테스트」를 「행동」이라는 말로 바꿔치는 발상 |
| 제6화 | 목의 이야기 | 목 객체의 이론화, 런던 학파와 디트로이트 학파(고전파)의 대립 |
| 제7화 | 속성 기반 테스트 | QuickCheck, Hypothesis — 「개별 예시」가 아니라 「성질」을 쓴다는 발상의 전환 |
Part III: 현장의 벽을 넘어(제8~10화)
브라우저와 프런트엔드라는 새로운 전장에서, 테스트가 어떻게 진화했는지를 따라간다.
| 화 | 제목 | 내용 |
|---|---|---|
| 제8화 | E2E의 세대교체 | Selenium → Cypress → Playwright, 브라우저 자동화 도구의 세대교체 |
| 제9화 | 자바스크립트 테스트의 진화 | Jasmine → Jest, 프런트엔드 고유 테스트 문화의 발전 |
| 제10화 | 언어별 생태계의 현재 | Java/Kotlin·Python·Ruby·Rust·Go 등, 각 언어의 현재 표준 도구 |
Part IV: 설계와 기법(제11~13화)
「좋은 테스트란 무엇인가」를 기법으로 파고드는 시대.
| 화 | 제목 | 내용 |
|---|---|---|
| 제11화 | 테스트의 형태 | 테스트 피라미드·트로피·허니콤, 전략 모델의 용도 구분 |
| 제12화 | 단위 테스트의 설계와 계약 | 좋은 단위 테스트의 설계 원칙, 계약 테스트에 의한 결합 비용 절감 |
| 제13화 | 커버리지와 뮤테이션 | 커버리지 지표의 이론과 한계, 뮤테이션 테스트에 의한 「테스트의 강도」 측정 |
Part V: 현대의 실천과 한계(제14~18화)
조직·규모·AI라는 현대적 변수 속에서, 테스트는 어디로 향하는가를 따라간다.
| 화 | 제목 | 내용 |
|---|---|---|
| 제14화 | 플레이키 테스트와의 싸움 | 불안정한 테스트가 조직의 신뢰를 좀먹는 구조와, 검출·격리·근절의 사이클 |
| 제15화 | 테스트의 한계와 형식 기법 | 데이크스트라의 경구를 수학적으로 메우려는 형식 검증·모델 검사와의 관계 |
| 제16화 | 품질을 모두가 | QA라는 직능의 역사적 변천, 「품질은 모두의 책임」이라는 현대적 사고방식 |
| 제17화 | 대규모 개발의 테스트 | 모노레포·대규모 조직에서의 테스트 운용이라는 현실적 과제 |
| 제18화 | AI 시대의 테스트 | LLM에 의한 테스트 생성의 가능성과 함정, 「AI가 쓴 테스트를 어떻게 신뢰할 것인가」라는 새로운 물음 |
「버그를 찾는 것」에서 「변경을 가능케 하는 것」으로
테스트의 목적관 자체도 70년 사이에 몇 번이고 새로 칠해져 왔다. 1970년대 말, 마이어스는 테스트를 「오류를 찾을 의도를 갖고 프로그램을 실행하는 과정」으로 정의하며 파괴적인 행위로 자리매김했다. 1990년대, 켄트 벡이 TDD를 체계화하자 테스트는 「작성한 코드를 확인하는 것」에서 「구현의 설계를 이끄는 것」으로 의미를 바꾼다. 2000년대 이후, 지속적 전달(CD)의 보급과 함께 테스트는 개별 개발자의 안전망을 넘어, 「조직이 프로덕션 환경에 안전하게 변경을 전달하기 위한 사회적 인프라」라는 역할을 짊어지게 되었다.
이 의미의 변천을 좇는 것은 단순한 기술 연표를 훑어보는 것 이상의 의미를 지닌다. 각 시대가 테스트에 무엇을 기대했는지를 아는 것은, 왜 지금의 프랙티스 — TDD, CI, 커버리지 목표, 계약 테스트 등 — 가 이런 형태가 되었는지를 이해하는 지름길이 된다. 거꾸로 말하면, 지금 「당연하다」고 여겨지는 테스트의 방식도 언젠가 다른 전제 아래서 다시 만들어질 도중의 한 형태에 지나지 않는다.
테스트는 무엇을 보장하고, 무엇을 보장하지 않는가
본 시리즈를 관통해 몇 번이고 되돌아가는 경계선이 하나 더 있다. 테스트가 초록(통과)이라는 것은 「시도한 범위 안에서 오류가 발견되지 않았다」는 것만을 의미한다. 데이크스트라가 지적했듯이, 테스트는 거의 무한에 가까운 입력 중에서 유한개를 골라 실행하는 행위인 이상, 원리적으로 「버그가 하나도 존재하지 않는다」는 것까지는 증명할 수 없다. 이 한계를 수학적으로 메우려는 것이 형식 기법(제15화)이며, 한편 이 한계를 받아들인 채 「실무상 어디까지의 리스크라면 허용할 수 있는가」를 계속 판단하는 것이 현대의 테스트 전략(제11~13화, 제17화)이다. 테스트의 역사는 이 「보장할 수 있는 것과 없는 것」의 경계선을, 각 시대가 어떻게 다시 그어 왔는가의 기록이기도 하다.
자매 시리즈와의 관계
본 시리즈는 [수학의 계보]·[음악 이론의 계보]와 같은 「사고방식의 역사」를 다루는 시리즈다. 수학이 「증명」이라는 영위의 역사이고, 음악 이론이 「협화·불협화를 어떻게 파악하는가」의 역사이듯, 소프트웨어 테스트는 「프로그램의 올바름을 어떻게 확인하는가」라는 물음의 역사다. 세 시리즈에 공통되는 것은, 「지금의 방식은 처음부터 그랬던 것이 아니라, 논쟁과 시행착오 끝에 다다른 하나의 도달점에 지나지 않는다」는 관점이다.
어떤 독자를 상정하는가
본 시리즈는 다음과 같은 독자를 염두에 두고 있다.
- TDD·BDD·목·속성 기반 테스트 같은 용어를 듣거나 본 적은 있지만, 그 유래나 논쟁의 경위까지는 모르는 사람
- 팀의 테스트 전략(피라미드 구성, 커버리지 목표, 플레이키 대책 등)을 역사적 배경과 함께 다시 살펴보고 싶은 실무자
- 「왜 지금의 테스트 프랙티스가 이런 형태인가」를, 조각난 팁의 모음이 아니라 역사의 축적으로 이해하고 싶은 사람
앞으로의 읽는 법
통사로서 제1화부터 순서대로 읽으면, 1950년대의 미분화된 「디버깅」에서 2020년대의 AI 활용까지 하나의 흐름으로 따라갈 수 있다. 개별 기법(목, 속성 기반, 커버리지 등)에 흥미가 있다면, 해당하는 화만 골라 읽어도 좋다. 연도나 인물의 세부보다, 「왜 그 시대에 그 사고방식이 태어나, 무엇과 대립하고, 무엇을 남겼는가」라는 인과의 연결을 따라가는 것을, 본 시리즈는 중시한다.
다음 제1화에서는, 아직 「테스트」라는 말이 독립된 의미를 갖지 않았던 시대 — 디버깅과 테스트가 미분화되어 있던 1950년대 — 부터 이야기를 시작한다.