OpenAPI 명세(Specs)로부터 12,000개의 API 테스트를 생성하며 배운 점
요약
OpenAPI 명세를 활용해 12,000개의 API 테스트를 자동 생성하며 얻은 실무적 교훈을 다룹니다. 테스트 생성기 자체보다 불완전한 API 명세(스키마, 계약, 예시 값)를 개선하는 것이 더 큰 과제임을 강조합니다.
핵심 포인트
- API 명세는 단순 문서가 아닌 단일 진실 공급원(SSOT)이어야 함
- 대부분의 명세는 에러 응답 등 예외 케이스가 누락된 불완전한 상태임
- OpenAPI의 예시 값(Example Values)은 테스트 생성 품질에 결정적임
- 테스트 생성의 병목은 알고리즘이 아닌 명세의 품질 문제임
우리는 OpenAPI 명세(specification)로부터 API 테스트를 생성하면 테스트 케이스를 작성하는 반복적인 작업을 없앨 수 있을 것이라고 생각했습니다. 실제로 그랬습니다. 하지만 우리가 예상하지 못했던 점은, 이것이 우리의 API가 아닌 API 명세의 문제점을 얼마나 빠르게 드러내느냐 하는 것이었습니다.
수십 개의 프로젝트에 걸쳐 OpenAPI 명세로부터 12,000개 이상의 API 테스트를 생성한 후, 한 가지 사실이 분명해졌습니다:
가장 큰 병목 현상은 테스트 생성기(test generator)가 아니었습니다.
바로 API 명세(specification) 그 자체였습니다.
우리는 대부분의 시간을 생성 알고리즘을 개선하는 데 보낼 것이라고 예상했습니다.
하지만 대신, 우리는 불완전한 스키마(schemas), 모호한 계약(contracts), 그리고 일관성 없는 명세들을 수정하는 데 대부분의 시간을 보냈습니다.
만약 여러분이 OpenAPI로부터 테스트를 생성할 계획이라면, 다음은 우리를 가장 놀라게 했던 점들입니다.
OpenAPI 테스트 생성의 약속
대부분의 API 팀은 이미 OpenAPI 명세를 가지고 있습니다.
불행하게도, 많은 팀이 이를 계약(contract)이 아닌 문서(documentation)로 취급합니다.
그것은 기회를 놓치는 것입니다.
좋은 명세는 다음과 같은 것들을 생성할 수 있습니다:
- 요청 검증 (Request validation)
- 응답 검증 (Response validation)
- 스키마 단언 (Schema assertions)
- 네거티브 테스트 케이스 (Negative test cases)
- 인증 시나리오 (Authentication scenarios)
- 모의 서버 (Mock servers)
- SDKs
- 문서 (Documentation)
그리고, 당연히 자동화된 API 테스트도 가능합니다.
명세로부터 직접 테스트를 생성한다는 것은 개발자가 Postman 컬렉션이나 코드 기반 프레임워크 내에서 계약을 수동으로 다시 재현할 필요가 없음을 의미합니다.
명세가 단일 진실 공급원(single source of truth)이 됩니다.
적어도, 이론상으로는 그렇습니다.
우리가 실제로 생성한 것들
몇 달에 걸쳐 우리는 내부 프로젝트, 공개 API, 그리고 고객 명세로부터 수천 개의 엔드포인트(endpoints)를 처리했습니다.
그 모든 과정에서 우리는 대략 다음과 같은 것들을 생성했습니다:
- 12,000개 이상의 API 테스트 케이스
- 수백 개의 OpenAPI 명세
- 수천 개의 요청/응답 단언 (request/response assertions)
- 셀 수 없이 많은 스키마 검증 (schema validations)
API 자체는 흥미로운 부분이 아니었습니다.
명세가 흥미로운 부분이었습니다.
교훈 1: 대부분의 OpenAPI 명세는 80%만 완성되어 있다
한 가지 패턴이 즉시 나타났습니다.
개발자들은 해피 패스(happy path)만을 문서화합니다.
그 외의 모든 것들은 생략됩니다.
전형적인 예시는 다음과 같습니다:
누락된 에러 응답 (error responses):
responses:
200:
description: Success
하지만 다음과 같은 것들은 없습니다:
400
401
403
...
생성기(generator)는 계약(contract)에 존재하는 시나리오에 대해서만 테스트를 생성할 수 있습니다.
만약 명세(specification)가 유효성 검사 실패(validation failures)를 무시한다면, 생성된 테스트 스위트(test suite) 또한 이를 무시하게 됩니다.
교훈 2: 예시 값(Example Values)은 예상보다 더 중요하다
OpenAPI는 예시(examples)를 지원합니다.
많은 팀이 이를 무시합니다.
다음과 같이 작성하는 대신:
name:
type: string
이렇게 제공하십시오:
name:
type: string
example: John Doe
이는 생성되는 다음 항목들을 개선합니다:
- 요청 (Requests)
- 모의 응답 (Mock responses)
- 문서화 (Documentation)
- 테스트 가독성 (Test readability)
좋은 예시는 생성된 테스트의 품질을 극적으로 향상시킵니다.
교훈 3: Nullable은 Optional을 의미하지 않는다
이 부분은 놀라울 정도로 많은 잘못된 단언(assertions)의 원인이 되었습니다.
다음은 서로 다릅니다:
nullable: true
그리고
required: false
하나는 다음을 의미합니다:
"해당 속성(property)은 존재하지만, null을 포함할 수 있다."
다른 하나는 다음을 의미합니다:
"해당 속성이 아예 존재하지 않을 수도 있다."
생성된 테스트는 이 둘을 반드시 구분해야 합니다.
그렇지 않으면 완벽하게 유효한 응답이 잘못된 이유로 실패하게 됩니다.
교훈 4: 인증(Authentication)은 빈번하게 불충분하게 정의된다
많은 API가 다음과 같이 정의합니다:
security:
- bearerAuth: []
전역적으로(Globally).
그러면 개별 엔드포인트(endpoints)는 조용히 다르게 동작합니다.
어떤 것은 API 키를 요구합니다.
다른 것들은 인증을 무시합니다.
명세는 결코 현실을 반영하지 못했습니다.
테스트 생성은 이러한 불일치(inconsistencies)를 즉각적으로 드러냈습니다.
교훈 5: 스키마(Schemas)는 팀이 깨닫는 것보다 더 빠르게 드리프트(drift)된다
한 엔드포인트는 다음과 같이 반환합니다:
{
"userId": 123
}
다른 엔드포인트는 다음과 같이 반환합니다:
{
"id": 123
}
둘 다 동일한 리소스(resource)를 나타냅니다.
둘 다 수동 테스트(manual testing)를 통과했습니다.
둘 다 문서화된 계약(contract)과 일관되게 일치하지 않았습니다.
생성된 테스트는 수년간 누적된 스키마 드리프트(schema drift)를 부각시켰습니다.
생성기가 추론할 수 있었던 것
현대의 생성기들은 놀라울 정도로 유능합니다.
그들은 다음과 같은 것들을 추론할 수 있습니다:
- 필수 요청 본문 (Required request bodies)
- 경로 파라미터 (Path parameters)
- 쿼리 파라미터 (Query parameters)
- 상태 코드 (Status codes)
- JSON 스키마 단언 (JSON schema assertions)
- 인증 요구 사항 (Authentication requirements)
단 하나의 명세(specification)로부터 말이죠.
하지만 그들은 비즈니스 규칙(business rules)은 추론할 수 없습니다.
여전히 인간의 입력이 필요한 부분
예를 들어:
discount = 110%
이것이 유효해야 할까요?
스키마는 이에 대해 답할 수 없습니다.
주문을 생성하면 재고를 줄여야 할까요?
스키마는 알지 못합니다.
중복된 이메일 주소에 대해 409 또는 422를 반환해야 할까요?
오직 비즈니스만이 이를 정의할 수 있습니다.
생성된 테스트는 인간이 설계한 시나리오를 대체하는 것이 아니라 보완하는 것입니다.
가장 큰 놀라움
우리는 개발자들이 다음과 같이 물을 것이라고 예상했습니다:
"생성기가 얼마나 정확한가요?"
하지만 그들은 대신 이렇게 물었습니다:
"왜 생성기가 내 명세(specification)에서 실패하나요?"
대부분의 경우 답은 간단했습니다.
명세가 실제로 유효하지 않았던 것입니다.
또는 불완전했습니다.
도구는 단지 항상 존재해 왔던 문제들을 드러냈을 뿐입니다.
생성기가 명세 검증기(Spec Validator)가 되다
예상치 못한 결과 중 하나는 팀들이 테스트를 생성하기 전에 명세를 수정하기 시작했다는 점입니다.
생성기는 효과적으로 품질 게이트(quality gate)가 되었습니다.
개발자들은 운영 환경(production)에서 계약(contract) 문제를 발견하는 대신, 생성 과정 중에 문제를 발견했습니다.
그 피드백 루프는 훨씬 저렴했습니다.
우리가 발견한 공통적인 명세 문제들
수백 개의 명세를 살펴보며 동일한 문제들이 반복적으로 나타났습니다:
- 필수 속성 누락 (Missing required properties)
- 잘못된 데이터 타입 (Incorrect data types)
- 유효하지 않은 예시 (Invalid examples)
- 일관성 없는 명명 규칙 (Inconsistent naming)
- 응답 스키마 누락 (Missing response schemas)
- 정의되지 않은 인증 (Undefined authentication)
- 중복된 모델 (Duplicate models)
- 모호한 Nullable 필드 (Ambiguous nullable fields)
이들 대부분은 테스트 문제가 아니었습니다.
명세 문제였습니다.
우리의 워크플로우에서 변경한 점
오늘날 우리의 프로세스는 다음과 같습니다:
API 설계 (Design API)
↓
...
무엇이 빠져 있는지 보이시나요?
테스트 케이스의 수동 재생성입니다.
계약(contract)이 거의 모든 것을 주도합니다.
인간의 테스트가 여전히 승리하는 영역
자동 생성은 다음과 같은 경우에 환상적입니다:
- 스키마 검증 (Schema validation)
- 필수 필드 (Required fields)
- 인증 (Authentication)
- 파라미터 조합 (Parameter combinations)
- 상태 코드 (Status codes)
인간은 여전히 다음과 같은 항목에 대해 테스트를 작성합니다:
- 비즈니스 규칙 (Business rules)
- 복잡한 워크플로 (Complex workflows)
- 성능 (Performance)
- 보안 (Security)
- 사용자 여정 (User journeys)
두 방식은 함께 사용할 때 가장 효과적입니다.
가장 큰 생산성 향상
가장 큰 이점은 테스트를 적게 작성하는 것이 아니었습니다.
그것은 중복된 작업을 제거하는 것이었습니다.
이전에는 개발자들이 API를 세 번 설명해야 했습니다:
- OpenAPI 명세 (OpenAPI specification)
- Postman 컬렉션 (Postman collection)
- 자동화된 테스트 (Automated tests)
이제 명세가 반복적인 작업의 상당 부분을 자동으로 생성합니다.
팀은 계약(contract)을 재현하는 대신 동작을 테스트하는 데 더 많은 시간을 할애합니다.
오늘 시작하는 팀에게 권장하는 사항
OpenAPI 기반 테스트를 도입한다면:
- 명세를 코드처럼 취급하세요.
- 지속적으로 검증하세요.
- 예시(examples)를 현실적으로 유지하세요.
- Null 허용 필드(nullable)와 선택적 필드(optional)를 분리하세요.
- 생성 후 비즈니스 단언(business assertions)을 추가하세요.
- 모든 CI 파이프라인에서 생성된 테스트를 실행하세요.
명세가 좋아질수록, 생성된 테스트도 좋아집니다.
마치며
12,000개의 API 테스트를 생성하며 우리는 예상치 못한 것을 배웠습니다.
가장 어려운 부분은 자동화가 아니었습니다.
명확하고 정확한 API 계약(contract)을 만드는 것이었습니다.
OpenAPI는 단순한 문서가 아닙니다.
잘 구축된다면, 이는 문서화, SDK 생성, 모의 서버(mock servers), 계약 검증(contract validation) 및 자동화된 테스트를 위한 토대가 됩니다.
생성된 테스트의 품질은 거의 항상 명세의 품질을 반영할 것입니다.
이 방식에 관심이 있다면, 저희는 **OpenAPI 테스트 자동화**에 대해 더 자세히 기록해 두었습니다.
최고의 API 테스트는 테스트 프레임워크에서 시작되지 않습니다.
잘 작성된 계약(contract)에서 시작됩니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기