본문으로 건너뛰기
중급약 28분

API 테스트로 커버리지 올리기: 무엇을 얼마나 덮었는지 재는 법

"API 테스트 100개 있습니다"는 아무것도 말해주지 않는다. 커버리지를 네 층으로 나눠 측정하고, 늘릴 순서를 정하고, 그 숫자를 보고 가능한 형태로 만든다.

  • #API커버리지
  • #OpenAPI
  • #실패경로
  • #커버리지측정
  • #테스트전략

개념

"테스트 100개 있습니다"가 답하지 못하는 것

API 자동화를 어느 정도 쌓은 팀에서 이런 대화가 오간다.

팀장: 우리 API 테스트 얼마나 돼요? QA: 100개쯤 있고 다 통과합니다. 팀장: 그럼 안심해도 되나요? QA: ...

마지막 침묵의 이유는 분명하다. 100이라는 숫자가 "무엇을 덮었는가"를 말해주지 않기 때문이다. 100개가 전부 로그인 API의 정상 케이스일 수도 있고, 결제 API는 하나도 없을 수도 있다.

모듈 6(레슨 5)에서 품질 지표를 배울 때 같은 문제를 봤다 — 개수는 지표가 아니다. 이 레슨은 API 테스트에서 "얼마나 덮었는가"를 실제로 재는 방법을 다룬다.

커버리지는 네 층으로 나뉜다

API 커버리지를 하나의 숫자로 만들려는 시도가 실패하는 이유는, 서로 다른 질문 네 개가 섞여 있기 때문이다.

① 엔드포인트 커버리지    어떤 API를 건드려는 봤는가
        ↓  (가장 얕다. 그러나 여기가 비면 나머지는 의미 없다)
② 응답·상태 커버리지     각 API의 어떤 결과 경로를 봤는가
        ↓  (200만 보고 있지 않은가)
③ 파라미터·입력 커버리지  어떤 입력 조합을 봤는가
        ↓  (경계값·필수/선택·타입)
④ 시나리오 커버리지      실제 사용자 흐름을 이어서 봤는가
                        (개별 API는 통과하는데 흐름은 깨지는 경우)

각 층이 답하는 질문과 재는 법을 표로 정리하면 이렇다.

층분모분자재기 난이도
① 엔드포인트스펙에 정의된 (경로 × 메서드) 수테스트가 한 번이라도 호출한 수낮음
② 응답·상태스펙에 정의된 응답 코드 수실제로 발생시킨 응답 수중간
③ 파라미터필드 × 유효/무효/경계실제로 시도한 조합높음
④ 시나리오핵심 사용자 여정 수끝까지 검증한 여정 수중간(정의하기 나름)

①부터 시작하는 것이 정석이다. 재기 쉽고, 여기가 비어 있으면 아래 층을 논할 이유가 없기 때문이다.

엔드포인트 커버리지 — 스펙과 대조한다

모듈 12(레슨 4)에서 OpenAPI 스펙으로 계약을 검증하는 법을 배웠다. 같은 스펙이 커버리지의 분모 로도 쓰인다.

OpenAPI 스펙에 정의된 것        우리 테스트가 호출하는 것
  GET    /orders                    ✓
  POST   /orders                    ✓
  GET    /orders/{id}               ✓
  PATCH  /orders/{id}               ✗   ← 빈칸
  DELETE /orders/{id}               ✗   ← 빈칸
  POST   /orders/{id}/cancel        ✗   ← 빈칸
  GET    /coupons                   ✓
  POST   /coupons/apply             ✗   ← 빈칸
 
  엔드포인트 커버리지 = 4 / 8 = 50%

재는 방법은 두 갈래다.

(a) 정적 대조 — 스펙의 경로 목록과 테스트 코드에서 호출하는 경로 목록을 뽑아 비교한다. 간단한 스크립트로도 된다.

(b) 실행 기록 기반 — 테스트를 돌릴 때 프록시나 서버 로그로 실제 호출된 경로를 수집해 스펙과 대조한다. 정확하지만 준비가 조금 더 든다.

(b)가 더 정직하다. 테스트 코드에 호출 코드가 있어도 조건 분기로 실제로는 안 돌 수 있기 때문이다.

중요한 전제: 이 측정은 스펙이 최신일 때만 의미가 있다. 스펙에 없는 엔드포인트가 운영에 떠 있으면, 커버리지 100%가 나와도 실제로는 절반만 덮은 것이다. 모듈 25(레슨 3)에서 배운 "설명서와 제품의 불일치" 가 여기서 커버리지 지표를 오염시킨다.

실패 경로가 진짜 커버리지다

②층에서 가장 흔한 함정이 이것이다.

200만 테스트하고 있다.

정상 응답은 개발자도 확인한다. QA가 봐야 할 것은 그 바깥이다.

확인해야 할 응답구체적으로
400 검증 오류필수 필드 누락, 타입 불일치, 형식 위반, 길이 초과
401 / 403 인증·인가토큰 없음·만료·위조, 다른 사용자 자원 접근
404없는 리소스, 삭제된 리소스
409 충돌중복 생성, 동시 수정
422 비즈니스 규칙 위반재고 부족, 쿠폰 만료, 한도 초과
429레이트 리밋
5xx 처리의존 서비스 장애 시 어떻게 되는가

403이 특히 자주 빠진다. "다른 사용자의 주문을 조회하면 어떻게 되나" 같은 케이스다. UI에서는 그 화면에 갈 방법이 없으니 테스트하지 않는데, API는 직접 호출할 수 있다. 모듈 16(레슨 5)의 OWASP 계열 취약점 중 접근 통제 실패 가 이 지점에서 나온다.

그 밖에 API 테스트에서 놓치기 쉬운 검증 항목들이다.

  • 멱등성 — 같은 요청을 두 번 보내면? 결제·주문 생성에서 치명적이다
  • 페이지네이션 경계 — 0건, 1건, 마지막 페이지, 범위 밖 페이지
  • 정렬·필터 조합 — 값이 없을 때, 잘못된 필드명일 때
  • 부분 실패 — 벌크 요청에서 일부만 실패하면 응답이 어떻게 되나
  • 필드 누락 vs null vs 빈 문자열 — 모듈 4(레슨 6)에서 본 그 구분

파라미터·입력 커버리지 — 모듈 3이 여기서 쓰인다

③층은 조합 폭발이 일어나는 곳이다. 필드가 10개면 조합은 감당 불가능해진다. 그래서 모듈 3에서 배운 설계 기법을 그대로 적용 한다.

기법API 테스트에서
동등분할(레슨 1)유효 그룹 / 무효 그룹 / 경계 그룹으로 나눈다
경계값 분석(레슨 1)최소·최대 길이, 0, 음수, 최대 정수
결정 테이블(레슨 3)여러 파라미터의 조합 규칙
페어와이즈(레슨 5)조합 수를 현실적으로 줄인다

페어와이즈가 API에서 특히 값을 한다. 파라미터 6개에 각 3값이면 전조합은 729개지만, 페어와이즈로는 20개 안팎으로 줄어든다. 그러면서도 "두 파라미터의 조합에서 나는 결함"의 대부분을 잡는다.

스펙 기반 자동 생성 도구를 쓰는 방법도 있다. OpenAPI 스펙에서 타입· 제약을 읽어 자동으로 무효 입력을 만들어 던지는 방식이다. 사람이 생각하지 못한 입력을 시도한다는 게 장점이고, 생성된 케이스가 우리 비즈니스 규칙까지는 모른다 는 게 한계다. 둘을 함께 쓰는 것이 현실적이다.

실사용 분포와 대조하기 — 가장 값진 확인

여기가 이 레슨에서 가장 실용적인 부분이다. 커버리지를 스펙하고만 대조하면 놓치는 것이 있다.

아무도 안 쓰는 API를 열심히 테스트하고, 가장 많이 쓰이는 API를 대충 테스트하고 있을 수 있다.

운영 로그(또는 API 게이트웨이 통계)에서 엔드포인트별 호출량 을 뽑아 우리 테스트 분포와 나란히 놓아본다.

엔드포인트월 호출량테스트 수판정
GET /products4,200만3불균형 — 보강 필요
POST /orders180만12적절
GET /orders/{id}320만4보강 검토
POST /admin/batch4015과투자
DELETE /coupons/{id}12,0000공백

이 표를 만들면 대화가 달라진다. "테스트를 늘려야 합니다"가 아니라 "월 4,200만 건 호출되는 상품 조회에 테스트가 3개입니다" 가 된다. 모듈 4에서 배운 리스크 기반 사고에 실사용 데이터 라는 축을 더하는 것이다.

호출량만이 아니라 장애 이력 을 함께 보면 더 좋다. 과거에 사고가 났던 엔드포인트는 다시 날 가능성이 높다.

커버리지를 올리는 순서

무작정 개수를 늘리면 유지보수 부채만 늘어난다(모듈 11 레슨 4). 순서가 있다.

1순위  스펙에 있는데 테스트가 0개인 엔드포인트
         → 빈칸부터 메운다. 가장 값싸고 효과가 크다
 
2순위  실사용 상위 엔드포인트의 실패 경로
         → 많이 쓰이는 곳의 400·401·403·409
 
3순위  계약 위반 케이스
         → 스펙과 실제 응답의 불일치 (모듈 12 레슨 4)
 
4순위  핵심 시나리오(여정) 연결 테스트
         → 개별 API는 통과하는데 흐름이 깨지는 경우
 
5순위  파라미터 조합 확장
         → 페어와이즈로 현실적인 개수만

1순위와 2순위에서 대부분의 이득이 나온다. 3순위 이하는 팀의 여력에 따라 진행한다. 이 순서를 지키지 않고 5순위부터 하는 팀이 의외로 많은데, 조합을 아무리 늘려도 테스트가 0개인 엔드포인트는 여전히 0개 다.

시나리오 커버리지 — 개별 통과와 흐름 통과는 다르다

④층은 개수로 재기 어렵지만 중요하다. 개별 API가 전부 200을 반환해도 이어 붙이면 깨지는 경우가 있다.

개별 테스트 (전부 통과)
  POST /cart/items        → 201
  POST /orders            → 201
  POST /payments          → 201
 
시나리오 테스트 (실패)
  장바구니 담기 → 주문 생성 → 결제
     └ 주문 생성 시 장바구니가 비워지지 않아
       결제 후에도 장바구니에 상품이 남는다

상태 전이와 데이터 일관성 이 시나리오에서만 드러난다. 모듈 3(레슨 3)의 상태 전이 테스트를 API 수준에서 하는 것이라고 봐도 된다.

시나리오 커버리지는 "핵심 사용자 여정 N개 중 M개를 API로 검증"처럼 재는 것이 현실적이다. 모듈 14(레슨 7)에서 SLI를 핵심 여정 단위로 잡은 것과 같은 분류를 쓰면 지표들이 서로 맞물린다.

API 커버리지가 UI 테스트를 줄여주는가

자주 나오는 질문이다. 답은 "부분적으로, 조건부로" 다.

API로 덮으면 UI에서 줄일 수 있는 것UI에서 반드시 남겨야 하는 것
비즈니스 규칙 검증(할인 계산, 권한)화면 렌더링과 레이아웃
데이터 유효성 검사사용자 상호작용 흐름
오류 응답 처리브라우저·기기별 동작
다양한 입력 조합접근성
상태 전이API 응답을 화면이 제대로 그리는가

마지막 줄이 핵심이다. API가 옳게 응답해도 화면이 잘못 그릴 수 있다. 그래서 API 커버리지가 올라가면 UI 테스트의 개수 는 줄일 수 있지만 종류 를 없앨 수는 없다. 모듈 11(레슨 1)의 자동화 피라미드가 말하는 바가 정확히 이것이다 — 아래층을 두껍게 하면 위층을 얇게 할 수 있지만, 위층이 0이 되지는 않는다.

숫자를 어디에 보고할 것인가

측정했으면 보이게 만든다. 모듈 22(레슨 8)에서 만든 대시보드에 얹거나, CI 리포트로 남긴다.

보고할 때 좋은 형태는 단일 숫자가 아니라 층별 + 빈칸 목록 이다.

API 테스트 커버리지 (v2.4.0 기준)
  엔드포인트    38 / 52  (73%)
  실패 경로     주요 엔드포인트 20개 중 14개에 4xx 케이스 존재
  시나리오      핵심 여정 8개 중 6개 검증
 
  테스트가 없는 엔드포인트 (14개)
    DELETE /coupons/{id}        월 호출 12,000
    PATCH  /orders/{id}         월 호출 84,000   ← 우선 보강
    ...

빈칸 목록이 함께 있어야 행동으로 이어진다. 모듈 22 레슨 8에서 배운 대로, 행동을 부르지 않는 숫자는 대시보드에 둘 이유가 없다.

함정 — 커버리지가 목표가 되는 순간

마지막으로 경고를 하나 남긴다. 커버리지 지표에는 잘 알려진 부작용이 있다.

1) 숫자가 목표가 되면 얕은 테스트가 늘어난다. 엔드포인트를 한 번씩 호출만 하고 응답을 제대로 검증하지 않는 테스트로도 ①층 커버리지는 100%가 된다. 모듈 18c(레슨 3)에서 배운 가짜 테스트 의 API 버전이다.

2) 스펙이 낡으면 커버리지도 거짓말이 된다. 분모가 틀렸기 때문이다. 스펙 갱신이 커버리지 측정의 전제다.

3) 커버리지 100%가 품질 100%가 아니다. 모듈 25(레슨 3)에서 인증에 대해 한 이야기와 같다 — 최소선을 목표로 삼으면 팀은 최소선으로 수렴한다.

그래서 커버리지는 목표가 아니라 진단 도구 로 쓰는 것이 맞다. "어디가 비어 있는가"를 찾는 데 쓰고, 숫자 자체를 KPI로 걸지 않는다.

실무에서 왜 필요한가

API 테스트를 쌓다 보면 반드시 "이제 충분한가"라는 질문이 온다. 그때 개수로 답하면 대화가 끝나지 않는다. 층별 커버리지와 빈칸 목록으로 답하면 다음에 무엇을 할지가 함께 나온다.

실사용 분포와 대조하는 습관은 특히 값이 크다. 대부분의 팀에서 테스트 분포는 만들기 쉬운 순서 로 형성되어 있지, 중요한 순서가 아니다. 한 번 대조해보면 우선순위가 크게 바뀌는 경우가 많다.

그리고 이 작업은 QA가 조직에 근거를 제시하는 통로다. "테스트 인력이 더 필요합니다"보다 "월 4,200만 건 호출되는 엔드포인트에 실패 경로 테스트가 없습니다" 가 훨씬 강한 문장이다. 모듈 4에서 배운 리스크 기반 논증에 데이터가 붙는 셈이다.

실습 과제

과제 1 — 엔드포인트 커버리지 재기 (20분)

우리 API의 스펙(OpenAPI 문서, 없으면 API 문서)과 테스트 목록을 놓고 대조표를 만든다.

경로메서드테스트 있음비고

그리고 계산한다 — 엔드포인트 커버리지 = 테스트가 있는 수 / 전체 수

해설 보기

이 과제에서 자주 발견되는 것 두 가지.

(1) 스펙에 없는데 실제로 도는 엔드포인트. 개발 중 추가하고 문서를 안 고친 경우다. 이걸 발견하면 커버리지보다 먼저 스펙 갱신 프로세스 를 손봐야 한다. 분모가 틀리면 모든 측정이 무의미하다.

(2) 스펙에는 있는데 이미 없어진 엔드포인트. 반대 방향의 불일치다. 이건 커버리지를 낮게 보이게 만들지만, 실제로는 지워야 할 문서다.

두 경우 모두 모듈 25 레슨 3의 "설명서와 제품의 불일치"이고, 계약 테스트(모듈 12 레슨 4)를 돌리면 자동으로 잡힌다.

과제 2 — 실패 경로 점검 (20분)

과제 1에서 테스트가 있는 엔드포인트 중 5개를 골라, 어떤 응답 코드를 검증하고 있는지 표시한다.

엔드포인트2004004014034044095xx
✓

빈칸 중 반드시 있어야 할 것 을 골라 이유를 적는다.

해설 보기

거의 모든 팀에서 200 열만 채워져 있다. 그게 정상이고, 그래서 이 과제에 의미가 있다.

우선순위를 정한다면 403 → 400 → 409 순을 권한다. 403(다른 사용자의 자원 접근)은 보안 사고로 직결되고, 400(입력 검증)은 가장 흔한 결함 유형이며, 409(중복·충돌)는 결제·주문에서 치명적이다.

5xx는 성격이 다르다. 의존 서비스가 죽었을 때의 동작을 보려면 그 상황을 만들어야 하므로 준비가 필요하다. 모듈 16의 신뢰성 테스트 영역에 가깝다.

과제 3 — 실사용 분포와 대조하기 (20분)

운영 로그나 API 게이트웨이 통계에서 엔드포인트별 호출량을 뽑아 테스트 분포와 나란히 놓는다.

엔드포인트호출량테스트 수과거 장애 이력판정

'판정'은 공백 / 불균형 / 적절 / 과투자 중에서 고른다. 데이터를 구할 수 없다면 어디에 요청해야 하는지 를 적는다.

과제 4 — 보강 계획 세우기 (15분)

과제 1~3의 결과를 본문의 5단계 우선순위로 정리해 보강 계획을 만든다.

순위대상추가할 테스트 수예상 공수근거

계획을 만든 뒤 검증한다 — 1·2순위만 해도 리스크가 얼마나 줄어드는가? 전부 다 하지 않아도 되는 이유를 한 문단으로 쓴다.

자가 체크리스트

  • 테스트 개수가 커버리지 지표가 될 수 없는 이유를 설명할 수 있다
  • API 커버리지의 네 층을 열거하고 각각의 분모·분자를 말할 수 있다
  • OpenAPI 스펙을 커버리지의 분모로 쓰는 방법과 그 전제를 설명할 수 있다
  • 정적 대조와 실행 기록 기반 측정의 차이를 말할 수 있다
  • 200만 테스트하는 함정과, 우선 채워야 할 응답 코드를 들 수 있다
  • 403이 API 테스트에서 특히 중요한 이유를 설명할 수 있다
  • 멱등성·페이지네이션 경계·부분 실패 같은 놓치기 쉬운 항목을 열거할 수 있다
  • 모듈 3의 설계 기법을 API 파라미터 조합에 적용할 수 있다
  • 실사용 호출량과 테스트 분포를 대조하는 것이 왜 값진지 설명할 수 있다
  • 커버리지를 올리는 5단계 우선순위를 말할 수 있다
  • 개별 API 통과와 시나리오 통과가 다른 경우를 예로 들 수 있다
  • API 커버리지가 UI 테스트를 어디까지 줄여줄 수 있는지 판단할 수 있다
  • 커버리지를 목표가 아니라 진단 도구로 써야 하는 이유를 설명할 수 있다

흔한 실수

  • 개수로 커버리지를 보고한다. 100개가 어디를 덮었는지 말해주지 않는다.
  • 200만 검증한다. 정상 응답은 개발자도 확인한다. QA의 자리는 실패 경로다.
  • 403을 빠뜨린다. UI에서는 갈 수 없는 화면도 API는 직접 호출된다.
  • 낡은 스펙을 분모로 쓴다. 분모가 틀리면 커버리지 전체가 거짓말이 된다.
  • 파라미터 조합부터 늘린다. 테스트가 0개인 엔드포인트가 남아 있는 한 조합을 늘려도 빈칸은 그대로다.
  • 전조합을 시도한다. 페어와이즈로 현실적인 수로 줄인다.
  • 실사용 분포를 확인하지 않는다. 테스트 분포는 만들기 쉬운 순서로 형성되지, 중요한 순서가 아니다.
  • 개별 API 통과로 만족한다. 상태 전이와 데이터 일관성은 시나리오에서만 드러난다.
  • API 커버리지로 UI 테스트를 없애려 한다. 개수는 줄여도 종류는 남는다.
  • 커버리지를 KPI로 건다. 호출만 하고 검증하지 않는 얕은 테스트가 늘어난다.
  • 숫자만 보고하고 빈칸 목록을 안 준다. 행동으로 이어지지 않는다.

참고 자료

낯선 말 풀이

이 레슨에 나온 약어입니다. 본문에서도 처음 나올 때 점선으로 표시해 두었습니다 (제목과 링크 글자는 그대로 둡니다).

API — 응용 프로그램 인터페이스
프로그램끼리 주고받는 창구. 사람이 화면 버튼을 누르는 대신, 프로그램이 정해진 주소로 요청을 보내 답을 받는다.
QA — 품질보증
만든 것이 쓸 만한지 확인하고, 애초에 덜 망가지게 만드는 방법을 정하는 일. "테스트"는 그 일의 일부다.
OpenAPI — 오픈에이피아이 명세
창구가 어떤 주소로 무엇을 받고 무엇을 돌려주는지 정해진 형식으로 적어 둔 문서.
UI — 사용자 인터페이스
사람이 직접 보고 누르는 부분 — 화면, 버튼, 입력창.
OWASP — 오왁스프
웹과 앱 보안 자료를 공개로 만드는 비영리 단체. 취약점 목록과 점검 기준이 유명하다.
SLI — 서비스 수준 지표
실제로 재는 숫자 — 응답 시간, 성공률 같은 것.
CI — 지속적 통합
코드를 올릴 때마다 자동으로 합쳐서 빌드하고 시험까지 돌리는 방식.
KPI — 핵심 성과 지표
"잘되고 있는가" 를 대표로 보여 주는 몇 개의 숫자.
PICT — 픽트
조건이 여러 개일 때 시험할 조합을 알아서 줄여 뽑아 주는 무료 도구.

용어집 전체 보기

이 레슨의 실습

실습은 별도 저장소에서 진행합니다. 새 탭으로 열립니다.