[BACK-012][실무] 테스트로 확인하는 할 일 API 만들기 > IT 기술 공유

본문 바로가기
사이트 내 전체검색

IT 기술 공유

[BACK-012][실무] 테스트로 확인하는 할 일 API 만들기

페이지 정보

profile_image
작성자 기술팀장
댓글 0건 조회 73회 작성일 26-09-06 09:34

본문

[이번 수업]

할 일 제목을 받아 JSON으로 돌려주는 작은 API와 자동 테스트를 만듭니다. 서버를 직접 띄우지 않아도 정상·오류 요청을 반복 검증하는 구조를 익힙니다.

[선수지식]

BACK-002의 HTTP, BACK-003의 REST, BACK-005의 입력 검증, PY-011의 pytest를 알면 좋습니다. Python 가상환경을 준비하세요.

[학습목표]

1. 요청 본문의 모양과 검증 규칙을 선언한다.
2. 성공 201과 검증 실패 422를 테스트한다.
3. 애플리케이션 객체를 분리해 테스트와 실행에서 함께 쓴다.

[핵심개념]

테스트 가능한 서비스는 네트워크 실행과 업무 규칙이 강하게 얽히지 않습니다. 예제에서는 `app` 객체가 경로를 모으고, `TaskIn` 모델이 입력 계약을 맡으며, 경로 함수는 검증된 값만 처리합니다. 테스트 클라이언트는 실제 포트를 열지 않고도 HTTP 요청과 응답을 확인합니다.

201은 새 자원이 만들어졌음을, 422는 JSON 문법은 읽었지만 값이 정한 규칙을 통과하지 못했음을 뜻합니다. 성공뿐 아니라 빈 값과 경계값을 테스트해야 계약이 문서와 코드에서 함께 유지됩니다.

[따라하기]

macOS·Linux는 `python3 -m venv .venv`, Windows는 `py -m venv .venv`로 가상환경을 만드세요. 활성화는 각각 `. .venv/bin/activate`, `.venv\Scripts\Activate.ps1`입니다. 이어서 모든 운영체제에서 다음을 실행합니다.
```sh
python -m pip install "fastapi[standard]==0.141.1" "pytest==9.1.1"
```

app.py를 만듭니다.
```python
from fastapi import FastAPI
from pydantic import BaseModel, field_validator

app = FastAPI()

class TaskIn(BaseModel):
    title: str

    @field_validator("title")
    @classmethod
    def validate_title(cls, value: str) -> str:
        clean = value.strip()
        if not 1 <= len(clean) <= 50:
            raise ValueError("제목은 1~50자여야 합니다")
        return clean

@app.post("/tasks", status_code=201)
def create_task(task: TaskIn) -> dict:
    return {"id": "T1", "title": task.title}
```

test_app.py를 만듭니다.
```python
from fastapi.testclient import TestClient
from app import app

client = TestClient(app)

def test_create_task():
    response = client.post("/tasks", json={"title": " 문서 읽기 "})
    assert response.status_code == 201
    assert response.json() == {"id": "T1", "title": "문서 읽기"}

def test_reject_empty_title():
    response = client.post("/tasks", json={"title": "  "})
    assert response.status_code == 422
```

`pytest -q`를 실행하면 예상 결과는 `2 passed`입니다. 그다음 `fastapi dev app.py --host 127.0.0.1`로 로컬 서버를 띄우세요. macOS·Linux는 `curl -X POST http://127.0.0.1:8000/tasks -H 'Content-Type: application/json' -d '{"title":"문서 읽기"}'`로 확인할 수 있습니다. Windows PowerShell은 `Invoke-RestMethod -Method Post -Uri http://127.0.0.1:8000/tasks -ContentType application/json -Body '{"title":"문서 읽기"}'`를 사용합니다. 예상 응답은 id가 T1이고 title이 문서 읽기인 JSON입니다.

[흔한 실수]

경로 함수 안에서 모든 검증을 반복하거나 성공 사례만 시험하지 마세요. 테스트끼리 전역 데이터를 공유하면 실행 순서에 따라 결과가 달라질 수 있습니다. 상태 코드와 본문을 함께 확인합니다.

[보안 주의]

입력 검증은 인증·인가를 대신하지 않습니다. 예제는 본인 소유 로컬 환경과 가짜 데이터만 사용합니다. 외부 공개 전에는 본문 크기 제한, 인증, 요청 횟수 제한, 안전한 오류 응답과 TLS를 별도로 설계하세요.

[직접 해볼 과제]

제목이 51자인 요청과 title이 숫자인 요청을 테스트에 추가하세요. 두 요청 모두 422인지 확인합니다.

[확인문제]

1. 테스트에서 실제 포트를 열지 않는 방식의 장점은 무엇인가요?
2. 입력 모델과 경로 함수를 나누면 무엇이 단순해지나요?
3. 성공 응답의 상태 코드와 본문을 함께 검사해야 하는 이유는 무엇인가요?

[다음 학습]

DB-012에서 주문 데이터를 표로 설계하고 분석 쿼리까지 연결합니다.

[공식 참고 자료]

https://fastapi.tiangolo.com/tutorial/testing/
https://fastapi.tiangolo.com/tutorial/body/
https://pydantic.dev/docs/validation/latest/concepts/validators/
https://docs.pytest.org/en/stable/getting-started.html
https://www.rfc-editor.org/rfc/rfc9110.html
https://pypi.org/project/fastapi/

댓글목록

등록된 댓글이 없습니다.

회원로그인

회원가입

사이트 정보

회사명 : 회사명 / 대표 : 대표자명
주소 : OO도 OO시 OO구 OO동 123-45
사업자 등록번호 : 123-45-67890
전화 : 02-123-4567 팩스 : 02-123-4568
통신판매업신고번호 : 제 OO구 - 123호
개인정보관리책임자 : 정보책임자명

접속자집계

오늘
1,739
어제
5,103
최대
16,772
전체
772,793
Copyright © 소유하신 도메인. All rights reserved.