테스트 코드를 잔뜩 짜놨는데도 정작 버그는 못 잡고, 기능 하나 고칠 때마다 테스트가 우수수 깨진 경험 있으신가요?
결론부터 말씀드리면, 좋은 단위 테스트는 개수나 커버리지가 아니라 ’FIRST 원칙’을 지켰는지로 판가름 납니다. FIRST는 Fast(빠르게), Isolated(독립적으로), Repeatable(반복 가능하게), Self-validating(스스로 검증), Timely(적시에)의 앞글자예요.
이 다섯 가지만 기억하면 테스트가 짐이 아니라 든든한 안전망이 됩니다. 오늘은 하나씩, 제 경험을 곁들여 풀어볼게요.
FIRST 원칙, 한눈에 정리하면?
FIRST는 로버트 마틴(엉클 밥)이 저서 ’클린 코드’에서 소개하면서 널리 퍼진 원칙입니다.
글자마다 좋은 단위 테스트의 조건 하나를 담고 있어요.
| 글자 | 의미 | 핵심 |
|---|---|---|
| F | Fast | 수백 개를 몇 초 안에 |
| I | Isolated | 테스트끼리 서로 간섭 없이 |
| R | Repeatable | 언제 어디서 돌려도 같은 결과 |
| S | Self-validating | 통과/실패를 자동 판정 |
| T | Timely | 적절한 시점에 작성 |
하나씩 뜯어보겠습니다.
Fast, 왜 이렇게 빨라야 할까요?
단위 테스트는 빨라야 합니다. 정말요.
느리면 개발자가 안 돌리거든요. 한 번 돌리는 데 3분씩 걸리는 테스트 묶음은 어느 순간부터 커밋 전에만 겨우 돌리게 됩니다.
테스트는 코드를 고칠 때마다 부담 없이 수백 번 돌릴 수 있어야 제 몫을 합니다.
느려지는 가장 흔한 원인은 실제 DB, 네트워크, 파일 시스템 접근이에요. 이런 외부 의존성은 테스트 대역(Mock, Stub)으로 대체하는 게 정석입니다.
한 개당 몇 밀리초, 전체 수백 개를 몇 초 안에 끝내는 걸 목표로 잡으면 좋습니다.
Isolated, 테스트가 서로 간섭하면 안 되는 이유
각 테스트는 독립적이어야 합니다. 다른 테스트의 결과에 의존하면 안 돼요.
예를 들어 A 테스트가 만들어 둔 데이터를 B 테스트가 가져다 쓰면, A가 실패하는 순간 B도 덩달아 무너집니다. 실행 순서만 바뀌어도 결과가 달라지고요.
그래서 각 테스트는 자기가 쓸 데이터를 스스로 준비하고, 끝나면 깔끔하게 치워야 합니다.
아래는 매 테스트 전에 상태를 초기화하는 흔한 패턴이에요.
struct CalculatorTests {
let calculator: Calculator
init() {
// 매 테스트마다 suite 인스턴스가 새로 만들어짐 → 상태 공유 차단
calculator = Calculator()
}
}
이렇게 하면 어떤 테스트가 먼저 돌든 서로에게 영향을 주지 않습니다.
Repeatable & Self-validating, 결과가 흔들리면 안 됩니다
R, 반복 가능성부터 볼게요. 테스트는 몇 번을 돌려도, 어떤 환경에서 돌려도 같은 결과가 나와야 합니다.
오늘은 통과했는데 내일은 실패하는 테스트를 ’깨지기 쉬운(flaky) 테스트’라고 부르는데요. 신뢰를 무너뜨리는 주범입니다.
현재 시각이나 랜덤 값에 의존하면 이런 문제가 생기기 쉬워요. 시간을 다뤄야 한다면 고정된 값을 주입해서 통제하는 게 안전합니다.
S, 자기 검증도 중요합니다. 테스트는 통과인지 실패인지 스스로 판단해야 해요.
콘솔에 값을 찍어놓고 사람이 눈으로 확인하는 건 테스트가 아닙니다. #expect 같은 단언문으로 결과를 자동 판정하게 만들어야 합니다.
좋은 테스트는 초록불 아니면 빨간불, 둘 중 하나만 보여줍니다. ‘이게 맞나?’ 하고 사람이 고민하게 만들면 이미 실패한 테스트예요.
Timely, 테스트는 언제 짜는 게 좋을까요?
마지막 T는 적시성입니다. 테스트를 적절한 시점에 작성하라는 뜻이에요.
TDD(Test-Driven Development, 테스트 주도 개발)에서는 프로덕션 코드보다 테스트를 먼저 씁니다. 꼭 그 방식을 따르지 않더라도, 기능 구현과 가까운 시점에 함께 작성하는 게 핵심입니다.
기능을 다 만들고 몇 주 뒤에 테스트를 몰아서 짜려고 하면, 그땐 이미 테스트하기 어려운 구조로 굳어 있는 경우가 많거든요.
테스트를 나중 일로 미루지 않는 것, 그게 Timely의 핵심입니다.
마무리하며
FIRST는 외우기 위한 규칙이 아니라, 테스트가 답답하게 느껴질 때 어디가 어긋났는지 짚어주는 체크리스트에 가깝습니다.
느린가? 서로 얽혀 있나? 결과가 흔들리나? 사람 손을 타나? 너무 늦게 짜고 있나? 이 다섯 개만 점검해도 테스트의 질이 확 올라갑니다.
오늘부터 테스트 하나 짤 때 FIRST를 슬쩍 떠올려 보세요. 분명 든든한 동료가 되어줄 거예요.
