테스트란?
코드가 의도한 대로 동작하는지 확인하는 작업입니다.
보통 개발하면서 코드를 짜고 나서 직접 실행해보거나 print()로 값을 찍어보는 방식으로 확인하는데, 이게 사실 비공식적인 테스트입니다.
공식적인 테스트는 이 확인 과정을 코드로 작성해서 자동으로 반복 실행할 수 있게 만드는 것입니다.
# 직접 눈으로 확인하는 방식 (비공식)
result = add(2, 3)
print(result) # 5 나오면 됐다고 넘어감
# 테스트 코드로 작성하는 방식 (공식)
def test_add():
assert add(2, 3) == 5 # 틀리면 자동으로 오류 발생
테스트 코드를 쌓아두면 나중에 코드를 수정했을 때 기존 기능이 그대로인지 한 번에 검증할 수 있습니다.
TDD란?
Test Driven Development, 테스트 주도 개발입니다.
코드를 먼저 짜는 게 아니라 테스트를 먼저 작성하고, 그 테스트를 통과하는 코드를 짜는 개발 방식입니다.
일반적인 개발 흐름과 비교하면 순서가 반대입니다.
일반적인 흐름: 코드 작성 → 테스트 (잘 되는지 확인) → 버그 수정
TDD 흐름: 테스트 작성 → 코드 작성 → 리팩토링 → 반복
아직 구현도 안 했는데 테스트부터 작성하는 게 이상해 보이지만, 이게 TDD의 핵심입니다.
"이 함수가 어떻게 동작해야 하는가"를 먼저 정의하고, 그걸 만족하는 코드를 짜는 방식입니다.
TDD를 쓰는 이유
버그를 일찍, 정확하게 잡습니다
테스트 없이 개발하다가 나중에 버그가 생기면 어디서 문제가 생겼는지 추적하기 어렵습니다. 코드가 많아질수록 범위를 좁히는 게 힘들어집니다.
TDD는 기능을 작은 단위로 쪼개고, 각 단위마다 테스트를 쌓아가는 방식입니다. 새로 추가한 코드에서 테스트가 실패하면 그 코드가 문제라는 걸 바로 알 수 있습니다.
코드를 고쳐도 안심할 수 있습니다
테스트가 없는 코드는 고치기가 무섭습니다. A를 수정했는데 B가 망가지는 경우가 생겨도 알아챌 방법이 없습니다. 결국 잘 돌아가는 코드는 건드리기 싫어지고, 시간이 갈수록 코드가 엉켜갑니다.
테스트가 있으면 코드를 수정한 뒤 테스트를 돌려보는 것만으로 기존 기능이 그대로인지 확인할 수 있습니다. 리팩토링을 과감하게 할 수 있게 됩니다.
설계가 자연스럽게 좋아집니다
테스트를 먼저 짜려면 "이 함수가 뭘 입력받고 뭘 반환해야 하는지"를 코드를 짜기 전에 먼저 생각해야 합니다. 이 과정 자체가 설계입니다.
테스트하기 어려운 코드는 대부분 설계가 잘못된 코드입니다. 함수가 너무 많은 일을 하거나, 의존성이 복잡하게 엉켜있으면 테스트를 작성하기가 어렵습니다. TDD를 하다 보면 테스트하기 쉬운 구조, 즉 역할이 명확하고 독립적인 코드를 짜게 됩니다.
테스트 코드가 문서가 됩니다
잘 작성된 테스트는 "이 함수가 어떤 입력에 어떤 결과를 내야 하는지"를 코드로 보여줍니다.
README나 주석보다 오래되거나 틀릴 가능성이 낮습니다. 실제로 실행되는 코드이기 때문입니다.
나중에 코드를 다시 봤을 때, 또는 다른 사람이 볼 때 테스트 코드만 읽어도 동작 방식을 파악할 수 있습니다.
Red - Green - Refactor 사이클
TDD는 이 세 단계를 짧게 반복하는 방식으로 진행합니다.
🔴 Red — 실패하는 테스트 작성
아직 구현하지 않은 기능에 대한 테스트를 먼저 작성합니다. 실행하면 당연히 실패합니다.
# 아직 함수가 없는 상태에서 테스트 먼저 작성
def test_add():
assert add(2, 3) == 5 # NameError: name 'add' is not defined
테스트가 실패하는 것을 먼저 눈으로 확인하는 게 중요합니다. 처음부터 통과하면 테스트 자체가 잘못 작성됐거나, 이미 구현된 코드가 있다는 의미입니다.
🟢 Green — 테스트를 통과하는 최소한의 코드 작성
테스트를 통과시키는 것만 목표로 합니다. 완벽하지 않아도 됩니다. 이 단계에서는 깔끔한 코드보다 통과가 우선입니다.
def add(a, b):
return a + b
🔵 Refactor — 코드 정리
테스트가 통과된 상태에서 코드를 다듬습니다. 중복 제거, 변수명 정리, 구조 개선 등을 합니다. 리팩토링 후에도 테스트는 반드시 통과해야 합니다.
테스트가 있기 때문에 리팩토링 중에 기능이 망가지면 바로 알 수 있습니다.
테스트의 종류
| 종류 | 범위 | 설명 |
| Unit Test | 함수/클래스 단위 | 가장 작은 단위입니다. TDD에서 주로 작성합니다. |
| Integration Test | 모듈 간 연동 | 여러 컴포넌트가 함께 잘 동작하는지 확인합니다. |
| End-to-End Test | 전체 시스템 | 사용자 관점에서 전체 흐름을 테스트합니다. |
TDD에서는 주로 Unit Test를 작성합니다.
범위가 작을수록 어디서 문제가 생겼는지 빠르게 파악할 수 있습니다.
좋은 테스트의 조건 (FIRST 원칙)
| 원칙 | 설명 |
| Fast | 빠르게 실행되어야 합니다. 느리면 자주 돌리기 싫어집니다. |
| Independent | 테스트끼리 서로 영향을 주면 안 됩니다. 실행 순서가 달라져도 결과가 같아야 합니다. |
| Repeatable | 언제, 어디서 실행해도 같은 결과가 나와야 합니다. |
| Self-validating | 통과/실패를 자동으로 판단해야 합니다. 사람이 직접 결과를 해석하면 안 됩니다. |
| Timely | 코드 작성 전(또는 직후)에 작성해야 합니다. 나중에 몰아서 쓰면 TDD가 아닙니다. |
TDD 실전 흐름 요약
1. 구현할 기능을 작은 단위로 쪼갠다.
2. 그 단위에 대한 테스트를 작성한다. (Red)
3. 테스트를 통과하는 최소한의 코드를 작성한다. (Green)
4. 코드를 정리한다. (Refactor)
5. 다음 기능으로 넘어가 1~4를 반복합니다.
한 번에 너무 많은 기능을 테스트하려 하면 사이클이 길어져서 TDD의 이점이 줄어듭니다. 작게 쪼개는 게 핵심입니다.
'BI&Programming-Tools > Python' 카테고리의 다른 글
| [Python TDD] pytest (0) | 2026.06.24 |
|---|---|
| [Python TDD] unittest (0) | 2026.06.24 |
| Python 커맨드 라인 인자 받기 — sys.argv & argparse (0) | 2026.06.23 |
| [파이썬 기초] 차원 축소 (PCA, UMAP) (0) | 2026.06.21 |
| [파이썬 기초] 데이터 전처리 심화 (결측값, 이상값, 정규화, 인코딩) (0) | 2026.06.20 |
