C.W.K.
Stream
Lesson 11 of 12 · published

AI 서비스 API 테스트

~10 min · api, testing, contract

Level 0Apprentice
0 XP0/101 lessons0/10 achievements
0/120 XP to next level120 XP to go0% complete

Wrapper API 는 contract 묶임; 뒤 모델은 아님

AI 서비스는 CI 에서 test 할 layer 두 개:

  • API layer — request/response shape, status code, auth, rate limit. 정통 contract test.
  • Model layer — 의미 / 행동 정확성. Eval 스타일 test.

첫 layer 는 downstream consumer 가 의존하는 것; 안정해야 함. 둘째 layer 는 합의된 범위 내에서 변동 허용.

API contract test

  • OpenAPI / Pydantic schema — 모든 response 가 문서화된 shape 에 검증.
  • Status code matrix — 빈 입력 → 400; unauthorized → 401; rate limit → 429; happy path → 200.
  • Streaming 프로토콜 — SSE / WebSocket 에 event 유형, chunk 구분자, 종료 event 단언.
  • 하위 호환성 — 필드 추가될 때 옛 클라이언트 동작 유지; deprecation 창 없이 필드 제거 절대 금지.

모델 mocking

API contract test 는 밑 모델 mock. 실제 모델 호출은 느리고 비싸고 비결정적. Schema 매치하는 canned response 반환하는 가짜 adapter 주입. Eval layer (별도 job) 가 실제 모델 동작 처리.

Code

FastAPI + Pydantic 으로 API contract test·python
# tests/test_api_contract.py
from fastapi.testclient import TestClient
from myapp.main import app, get_brain
from myapp.schemas import ChatResponse

class FakeBrain:
    async def stream(self, *a, **kw):
        yield {'type': 'text', 'text': 'hello'}
        yield {'type': 'done', 'usage': {'in': 5, 'out': 1}}

app.dependency_overrides[get_brain] = lambda: FakeBrain()
client = TestClient(app)

def test_chat_returns_documented_shape():
    r = client.post('/api/chat', json={'message': 'hi'})
    assert r.status_code == 200
    ChatResponse.model_validate(r.json())     # raises if shape drifts

def test_chat_rejects_empty_input():
    r = client.post('/api/chat', json={'message': ''})
    assert r.status_code == 400

External links

Exercise

AI 엔드포인트 하나에 contract test 5 개 작성: happy path, 빈 입력, 너무 큰 입력, auth 없음, rate-limit shape. 빠르고 결정적인 test 위해 fake brain 사용.

Progress

Progress is local-only — sign in to sync across devices.
이 페이지에서 버그를 발견하셨거나 피드백이 있으세요?문제 신고

댓글 0

🔔 답글 알림 (로그인 필요)
로그인댓글을 남기려면 로그인해 주세요.

아직 댓글이 없어요. 첫 댓글을 남겨보세요.