API 테스트란?Python(pytest+requests)으로 시작하는 자동화 입문

📌 이 글은 이런 분께 추천합니다

  • API 테스트가 무엇인지 알고 싶은 QA 엔지니어・개발자
  • UI 테스트와 API 테스트의 차이를 이해하고 싶은 분
  • Python으로 자동화 테스트를 시작하고 싶은 엔지니어
  • pytest와 requests의 사용법을 기초부터 배우고 싶은 분

이 글을 읽으면 알 수 있는 것

  • API 테스트와 UI 테스트의 차이와 사용 구분
  • requests 라이브러리로 HTTP 요청을 보내는 방법
  • pytest로 API 테스트를 자동 실행하는 기본 패턴
  • HTML 리포트를 자동 생성해서 포트폴리오에 활용하는 방법

👨‍💻 필자 소개

QA 엔지니어로서 실무에서 Playwright・Python・pytest를 사용한 API 테스트 자동화를 담당하고 있습니다. 본 글에서 사용하는 코드는 모두 GitHub에 공개되어 있으며, 실제로 동작 확인이 완료된 코드를 그대로 해설하고 있습니다.

「API 테스트는 어렵겠지…」라고 생각하고 있지는 않으신가요? 사실 requests와 pytest 두 가지 라이브러리를 조합하는 것만으로 실무 수준의 API 테스트를 작성할 수 있습니다.

이 글에서는 API 테스트의 기본 개념부터 환경 구축・실제 코드까지 꼼꼼하게 해설합니다. UI 테스트 경험밖에 없는 분도 글을 다 읽을 무렵에는 「API 테스트도 내가 직접 쓸 수 있다」는 자신감이 생길 것입니다.


00. API 테스트란?

API 테스트란, 애플리케이션의 「내부 구조(API)」가 올바르게 동작하는지 확인하는 테스트입니다.

UI 테스트가 브라우저를 조작해서 화면 전체를 확인하는 것과 달리, API 테스트는 브라우저를 사용하지 않고 HTTP 요청을 직접 전송하여 응답을 검증합니다.

UI 테스트 API 테스트
확인 대상 화면・외관・조작감 데이터・로직・보안
브라우저 필요 불필요
실행 속도 느림 🐢 매우 빠름 ⚡
깨지기 쉬움 UI 변경으로 쉽게 깨짐 로직이 바뀌지 않는 한 안정적

💡 포인트:UI 테스트와 API 테스트는 「어느 쪽이 더 좋다」가 아니라, 각각 역할이 다릅니다. 둘 다 할 수 있으면 QA 엔지니어로서의 가치가 크게 높아집니다.


01. API 테스트가 왜 중요한가?

현대의 웹 앱은 거의 모두 프론트엔드(화면)와 백엔드(API)가 분리된 구조로 되어 있습니다.

API가 망가지면 화면이 아무리 올바르게 표시되어 있어도 데이터가 저장되지 않거나・로그인이 안 되거나・결제가 실패하는 등 치명적인 문제가 발생합니다.

또한 API 테스트는 UI 테스트보다 10〜100배 빠르게 실행할 수 있기 때문에, CI/CD 파이프라인에 통합하여 매번 배포 전에 자동으로 확인하는 것이 실무의 정석입니다.

# API 테스트 이미지
# 브라우저 없이!코드만으로 서버와 통신한다

import requests

response = requests.get("https://jsonplaceholder.typicode.com/users/1")
print(response.status_code)  # 200
print(response.json())       # {"id": 1, "name": "Leanne Graham", ...}

💡 포인트:단 3줄로 API에 요청을 보내고 응답을 확인할 수 있습니다. 이것이 API 테스트의 기본 형태입니다.


02. 환경 구축

필요한 라이브러리 설치

아래 3가지를 설치하기만 하면 동작합니다.

pip install requests pytest pytest-html
라이브러리 역할
requests API에 HTTP 요청을 보낸다
pytest 테스트를 실행・관리한다
pytest-html HTML 리포트를 자동 생성한다

pytest.ini 설정

프로젝트 루트에 pytest.ini 를 두는 것으로, 테스트 실행 때마다 HTML 리포트가 자동 생성됩니다.

# pytest.ini
[pytest]
addopts = --html=report.html --self-contained-html

💡 Tip:한 번 설정해두면 이후로는 pytest test_api.py -v 만으로 자동으로 HTML 리포트가 생성됩니다. 포트폴리오 증거로도 활용할 수 있습니다.


03. requests 라이브러리 기본

HTTP 메서드 사용법

HTTP 메서드에 대응하는 메서드가 각각 준비되어 있습니다.

import requests

# GET: 데이터를 가져온다
response = requests.get("https://jsonplaceholder.typicode.com/users/1")

# POST: 데이터를 생성한다
response = requests.post(
    "https://jsonplaceholder.typicode.com/users",
    json={"name": "Taro", "email": "taro@example.com"}
)

# PUT: 데이터를 업데이트한다
response = requests.put(
    "https://jsonplaceholder.typicode.com/users/1",
    json={"name": "Updated Taro"}
)

# DELETE: 데이터를 삭제한다
response = requests.delete("https://jsonplaceholder.typicode.com/users/1")

응답 확인 방법

response = requests.get("https://jsonplaceholder.typicode.com/users/1")

print(response.status_code)  # 상태 코드: 200
print(response.json())       # 응답 바디(JSON 형식)
print(response.headers)      # 응답 헤더

💡 포인트:response.json() 을 사용하면 응답의 JSON을 Python 딕셔너리 형태로 다룰 수 있습니다. 그대로 어서션에 사용할 수 있어서 편리합니다.


04. pytest 기본

테스트 작성법

함수명을 test_ 로 시작하기만 하면 pytest가 자동으로 테스트로 인식합니다.

import requests

def test_get_user():
    """사용자 정보를 올바르게 가져올 수 있는지 확인"""
    response = requests.get("https://jsonplaceholder.typicode.com/users/1")

    assert response.status_code == 200, f"기댓값: 200, 실제: {response.status_code}"
    assert response.json()["id"] == 1
    assert "name" in response.json()

실행 커맨드

# 모든 테스트를 실행
pytest

# 상세 표시로 실행
pytest -v

# 특정 파일만 실행
pytest test_api.py -v

실행 결과 샘플

test_api.py::test_get_user       PASSED  [ 33%]
test_api.py::test_create_user    PASSED  [ 66%]
test_api.py::test_delete_user    PASSED  [100%]

3 passed in 1.23s ✅

💡 포인트:assert 가 실패했을 때는, 어떤 값이 기댓값과 달랐는지를 자동으로 표시해줍니다. 디버깅이 매우 편해집니다.


05. pytest + requests 조합하기

이 두 가지를 조합하면 실무 수준의 API 테스트를 작성할 수 있습니다. JSONPlaceholder라는 무료 목(mock) API를 사용해서 실제로 동작시켜 봅시다.

import requests
import pytest

BASE_URL = "https://jsonplaceholder.typicode.com"

def test_get_all_users():
    """모든 사용자를 가져올 수 있는지 확인"""
    response = requests.get(f"{BASE_URL}/users")

    assert response.status_code == 200
    assert len(response.json()) == 10  # 10명의 사용자가 반환될 것

def test_create_user():
    """사용자를 생성할 수 있는지 확인"""
    new_user = {"name": "Yoshitsugu", "email": "test@example.com"}
    response = requests.post(f"{BASE_URL}/users", json=new_user)

    assert response.status_code == 201
    assert response.json()["name"] == "Yoshitsugu"

def test_delete_user():
    """사용자를 삭제할 수 있는지 확인"""
    response = requests.delete(f"{BASE_URL}/users/1")

    assert response.status_code == 200

⚠️ 주의:JSONPlaceholder는 목(mock) API이므로 실제로는 데이터가 저장・삭제되지 않습니다. 학습용으로 안심하고 사용할 수 있습니다.


06. 자주 겪는 문제 & 해결법

구현 중 실제로 겪었던 문제들을 정리했습니다. 같은 곳에서 막히는 분들께 도움이 되면 좋겠습니다.


① requests와 pytest-requests를 혼동해버린다

처음에 「pytest로 HTTP 요청을 보내는 라이브러리」를 검색했더니 pytest-requests 라는 라이브러리를 찾아 설치해버렸습니다. 실제로 사용하는 것은 별개의 라이브러리로, requests(HTTP 클라이언트)와 pytest(테스트 프레임워크)를 조합해서 사용합니다.

# ❌ pytest-requests는 이번에 사용하지 않음
pip install pytest-requests

# ✅ 올바른 설치
pip install requests pytest pytest-html

💡 포인트:requests 는 HTTP 요청 전용, pytest 는 테스트 실행 전용입니다. 역할이 다르므로 둘 다 설치하여 사용합니다.


② response.json()에서 KeyError가 발생한다

응답의 JSON에서 값을 꺼내려고 했을 때 존재하지 않는 키를 지정해버려 KeyError 가 발생했습니다. 먼저 응답 내용을 확인하고 나서 접근하는 습관이 중요합니다.

# ❌ 키가 존재하지 않으면 KeyError 발생
user_id = response.json()["userId"]  # KeyError!

# ✅ 먼저 print()로 내용을 확인한다
print(response.json())
# {'id': 1, 'name': 'Leanne Graham', ...}

# ✅ get()을 사용하면 KeyError를 방지할 수 있다
user_id = response.json().get("id")  # 오류 대신 None을 반환

💡 포인트:처음 접하는 API는 반드시 print(response.json()) 로 응답 구조를 확인하고 나서 어서션을 작성합시다.


③ assert가 실패해도 원인을 알 수 없다

처음에는 assert response.status_code == 200 만 작성했기 때문에 실패했을 때 「무엇이 반환됐는지」를 알 수 없어 원인 조사에 시간이 걸렸습니다.

# ❌ 실패 시 정보가 적다
assert response.status_code == 200

# ✅ 에러 메시지를 추가해서 원인을 바로 파악
assert response.status_code == 200, f"기댓값: 200, 실제 값: {response.status_code}"

💡 포인트:assert 조건, "메시지" 형태로 메시지를 추가하면 실패 시에 기댓값과 실제 값이 무엇이었는지를 바로 알 수 있습니다.


④ 테스트 파일명・함수명 규칙을 몰랐다

pytest가 테스트를 자동으로 인식하지 못하는 경우가 발생했습니다. 원인은 파일명이나 함수명이 pytest의 명명 규칙을 따르지 않았기 때문이었습니다.

# ❌ pytest가 인식하지 못함
# 파일명: api_test.py(test_로 시작하지 않음)
def check_user():  # test_로 시작하지 않음
    assert True

# ✅ pytest가 자동으로 인식
# 파일명: test_api.py(test_로 시작)
def test_check_user():  # test_로 시작
    assert True

⚠️ 주의:파일명은 test_ 로 시작하거나 _test 로 끝나야 하고, 함수명은 test_ 로 시작해야 합니다. 이 두 가지가 pytest의 기본 규칙입니다.


⑤ BASE_URL 끝에 슬래시가 있어 URL이 이중으로 된다

BASE_URL 끝에 / 를 붙인 상태에서 경로를 결합했더니 URL이 //users 처럼 이중 슬래시가 되어버려 요청이 실패했습니다.

# ❌ 이중 슬래시가 되어버림
BASE_URL = "https://jsonplaceholder.typicode.com/"
response = requests.get(f"{BASE_URL}/users")
# → https://jsonplaceholder.typicode.com//users(NG)

# ✅ BASE_URL 끝의 슬래시를 제거
BASE_URL = "https://jsonplaceholder.typicode.com"
response = requests.get(f"{BASE_URL}/users")
# → https://jsonplaceholder.typicode.com/users(OK)

💡 포인트:BASE_URL 끝에는 / 를 붙이지 않고, 각 경로의 앞에 / 를 붙이는 방식으로 통일하면 혼란이 없습니다.


07. 자주 묻는 질문(FAQ)

Q. pytest로 API 테스트를 하는 장점은 무엇인가요?
A. Python으로 직관적으로 테스트를 작성할 수 있고 CI/CD와의 통합이 쉬운 것이 가장 큰 장점입니다. 또한 pytest-html 로 HTML 리포트를 자동 생성할 수 있어 테스트 증거 작성 공수를 대폭 줄일 수 있습니다.

Q. requests와 httpx 어느 쪽이 좋은가요?
A. 용도에 따라 구분하는 것이 최선입니다. 간단한 동기 처리라면 requests, 비동기 처리(async/await)가 필요하다면 httpx 를 선택하세요. API 테스트 입문에는 requests 가 더 간단하여 추천합니다.

Q. UI 테스트와 API 테스트 중 어느 것부터 시작해야 하나요?
A. API 테스트부터 시작하는 것을 추천합니다. 실행 속도가 빠르고 환경 설정도 간단하기 때문에 테스트 자동화의 기초를 배우기에 최적입니다. UI 테스트에 익숙한 분도 API 테스트를 추가함으로써 「둘 다 할 수 있는 엔지니어」로서 어필할 수 있습니다.

Q. 테스트 대상 API가 없는 경우는 어떻게 하면 되나요?
A. 연습용 공개 API를 사용합시다. JSONPlaceholder(사용자・게시물 CRUD)나 Restful Booker(인증 플로우)가 포트폴리오용 API 테스트에 최적입니다. 둘 다 무료로 사용할 수 있습니다.

Q. pytest의 fixture란 무엇인가요?
A. 테스트의 사전・사후 처리를 공통화하는 구조입니다. 예를 들어 인증 토큰 취득을 fixture에 작성해두면 여러 테스트 케이스에서 재사용할 수 있습니다. 코드의 중복을 줄이고 유지보수하기 쉬운 구조로 만들기 위한 중요한 기능입니다.


08. 정리

이 글에서는 API 테스트의 기본 개념과 pytest와 requests의 사용법을 해설했습니다.

포인트 내용
API 테스트란 브라우저 없이 HTTP 요청을 보내고 응답을 검증하는 테스트
requests의 역할 API에 HTTP 요청 전송・응답 취득
pytest의 역할 테스트 실행・관리・HTML 리포트 생성
조합의 강점 간단한 코드로 실무 수준의 API 테스트를 실현할 수 있다

UI 테스트 경험밖에 없는 분도, requests와 pytest 두 가지만 익히면 API 테스트를 작성할 수 있게 됩니다. GitHub에 코드를 공개함으로써 「UI도 API도 둘 다 할 수 있습니다!」라는 어필이 됩니다. 다음 글에서는 실제 API 테스트 케이스를 자세히 해설합니다.

タイトルとURLをコピーしました