테스트 코드를 짜다 보면 어느 순간 커버리지 숫자에 집착하게 됩니다.
“이왕이면 100% 채워야지” 하는 마음, 저도 잘 압니다.
결론부터 말씀드리면, 코드 커버리지는 70~80%대가 실무에서 가장 현실적이고, 100%가 곧 버그 없는 코드를 뜻하지는 않습니다. 왜 그런지 제 경험을 곁들여 풀어볼게요.
핵심 요약부터 먼저 볼게요
바쁘신 분들을 위해 이 글의 결론을 먼저 정리했습니다.
- 커버리지 100%는 “모든 줄이 실행됐다”일 뿐, “모든 경우가 검증됐다”가 아닙니다.
- 실무 권장치는 대체로 70~80% 선입니다.
- 결제·인증처럼 중요한 핵심 로직은 90% 이상을 노려도 좋습니다.
- 숫자보다 “무엇을 테스트하지 않았는가”를 아는 게 더 중요합니다.
코드 커버리지 100%면 버그가 없을까요?
가장 흔한 오해가 바로 이겁니다.
커버리지 100%는 테스트가 코드의 모든 줄을 “한 번은 실행했다”는 의미일 뿐이에요.
그 줄이 올바르게 동작하는지까지 검증했다는 뜻은 아닙니다.
예를 들어볼게요. 아래 함수는 테스트가 실행만 시키고 결과는 제대로 확인하지 않는 경우입니다.
func divide(_ a: Double, _ b: Double) -> Double {
return a / b // b가 0이면? 테스트가 실행은 하지만
}
// 이 테스트는 커버리지 100%지만
@Test func divide_실행만_한다() {
_ = divide(10, 2) // 반환값을 검증(#expect)하지 않음!
}
이 코드는 커버리지 100%를 찍습니다.
하지만 #expect로 결과를 확인하지 않으니 사실상 아무것도 보장하지 못하죠.
커버리지는 “얼마나 실행했나”를 재는 자이지, “얼마나 잘 검증했나”를 재는 자가 아닙니다.
숫자만 보고 안심하면 안 되는 이유가 바로 이겁니다.
그래서 몇 퍼센트가 적당할까요?
여러 팀을 거치며 제가 체감한 현실적인 기준을 표로 정리해봤습니다. (2026년 기준 일반적인 실무 권장치)
| 코드 영역 | 권장 커버리지 | 이유 |
|---|---|---|
| 핵심 비즈니스 로직 | 90% 이상 | 결제·인증 등 오류 시 치명적 |
| 일반 서비스 코드 | 70~80% | 비용 대비 효과가 가장 좋은 구간 |
| UI·뷰 계층 | 50~60% | 변경이 잦고 테스트 유지비 큼 |
| 자동 생성·설정 파일 | 측정 제외 | 테스트 의미가 적음 |
구글도 내부적으로 60%를 “받아들일 만한 수준”, 75%를 “권장”, 90%를 “모범”으로 본다고 공개한 적이 있어요.
딱 정해진 정답은 없지만, 80% 근처가 대부분의 팀에게 합리적인 목표라고 보시면 됩니다.
왜 100%를 고집하면 오히려 손해일까요?
마지막 20%를 채우는 데 드는 노력이 앞의 80%를 채우는 것보다 훨씬 큽니다.
예외 처리, 도달하기 어려운 분기, 방어 코드까지 전부 테스트하려면 시간이 기하급수적으로 늘어나요.
더 큰 문제는 따로 있습니다.
숫자를 채우려고 만든 “보여주기식 테스트”가 생긴다는 점이에요.
정작 검증은 안 하면서 커버리지만 올리는 테스트는 나중에 코드를 바꿀 때 발목만 잡습니다.
리팩터링할 때마다 의미 없는 테스트를 고치느라 시간을 쓰게 되죠.
자주 묻는 질문 (Q&A)
Q. 그럼 커버리지 측정 자체가 의미 없나요?
아니요. 커버리지는 “테스트가 아예 안 닿은 영역”을 찾는 데 아주 유용합니다.
숫자를 목표로 삼기보다, 커버리지 리포트에서 빨간 부분(미실행 코드)을 확인하는 용도로 쓰세요.
Q. CI에 커버리지 기준을 강제로 걸어도 될까요?
걸어도 되지만 “신규 코드는 80% 이상” 같은 방식을 추천해요.
전체 코드에 일괄로 높은 기준을 걸면 기존 코드 때문에 팀 전체가 지칩니다.
Q. 커버리지 종류가 여러 개던데요?
라인 커버리지보다 브랜치(분기) 커버리지를 함께 보는 게 좋습니다.
if/else 같은 조건 분기가 제대로 테스트됐는지가 실제 품질과 더 가깝거든요.
숫자에 쫓기지 마시고 “이 테스트가 정말 무언가를 지켜주고 있나”부터 물어보세요.
커버리지 80%짜리 탄탄한 테스트가 100%짜리 껍데기 테스트보다 훨씬 든든합니다. 오늘도 좋은 테스트 코드 작성하시길 응원할게요!
