๐ ์ด ๊ธ์ ์ด๋ฐ ๋ถ๊ป ์ถ์ฒํฉ๋๋ค
- Python๊ณผ requests๋ก DELETE ์์ฒญ ํ ์คํธ๋ฅผ ์์ฑํ๊ณ ์ถ์ ๋ถ
- API ํ ์คํธ์์ ๋ฐ์ดํฐ ์ญ์ ๊ฒ์ฆ ๋ฐฉ๋ฒ์ ๋ฐฐ์ฐ๊ณ ์ถ์ QA ์์ง๋์ด
- CRUD ์กฐ์์ API ํ ์คํธ๋ฅผ ์์ฑํ๊ณ ์ถ์ ๋ถ
- ์ญ์ ํ 404 ํ์ธ๊น์ง ํฌํจํ ๊ฒฌ๊ณ ํ DELETE ํ ์คํธ๋ฅผ ๊ตฌํํ๊ณ ์ถ์ ๋ถ
โ ์ด ๊ธ์ ์ฝ์ผ๋ฉด ์ ์ ์๋ ๊ฒ
- pytest์ requests๋ก DELETE ์์ฒญ API ํ ์คํธ๋ฅผ ์์ฑํ๋ ๊ธฐ๋ณธ ํจํด
- ์ญ์ ์ฑ๊ณต ์ ์ํ ์ฝ๋๏ผ200ใป204๏ผ์ ์ฐจ์ด์ ์ฌ์ฉ ๊ตฌ๋ถ
- ์ญ์ ํ 404๊ฐ ๋ฐํ๋๋ ๊ฒ์ ํ์ธํ๋ ๊ตฌํ ๋ฐฉ๋ฒ
- raise_for_status()๋ฅผ ์ฌ์ฉํ ์ค๋ฌด ์์ค์ ํ ์คํธ ์ฝ๋ ์์ฑ๋ฒ
Python์ผ๋ก API ํ ์คํธ๋ฅผ ์์ฑํ ๋ CRUD ์กฐ์์ ๋ง์ง๋ง์ด DELETE ์์ฒญ ํ ์คํธ์ ๋๋ค. pytest์ requests๋ฅผ ์ฌ์ฉํ๋ฉด API์ ์ญ์ ์ฒ๋ฆฌ๊ฐ ์ฌ๋ฐ๋ฅด๊ฒ ๋์ํ๋์ง๋ฅผ ์๋ ํ ์คํธ๋ก ๊ฒ์ฆํ ์ ์์ต๋๋ค.
์ด ๊ธ์์๋ DELETE ํ ์คํธ์ ๊ธฐ๋ณธ๋ถํฐ ์ญ์ ํ 404 ํ์ธ๊น์ง๋ฅผ ์ค๋ฌด์์ ์ฌ์ฉํ ์ ์๋ ์ฝ๋์ ํจ๊ป ์๊ฐํฉ๋๋ค.
- 00. API ํ ์คํธ์ DELETE ์์ฒญ์ ๊ธฐ๋ณธ
- 01. pytest + requests์ API ํ ์คํธ ํ๊ฒฝ
- 02. Python์ผ๋ก API DELETE ํ ์คํธ๋ฅผ ์์ฑํ๋ ๋ฐฉ๋ฒ
- 03. API ํ ์คํธ DELETE ํ ์ํ ํ์ธ
- 04. API ํ ์คํธ DELETE ์ด์๊ณ ํจํด
- 05. API ํ ์คํธ DELETE ํค๋ ๊ฒ์ฆ
- 06. DELETE ํ ์คํธ ์ ์ฒด ์ฝ๋
- 07. ์์ฃผ ๊ฒช๋ ๋ฌธ์ & ํด๊ฒฐ๋ฒ
- โ ์ญ์ ์ฑ๊ณต์ด 200์ธ์ง 204์ธ์ง ํท๊ฐ๋ฆฐ๋ค
- โก 204์ผ ๋ response.json()์์ ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ค
- โข ๋ชฉ API์์ ์ญ์ ํ 404๋ฅผ ํ์ธํ ์ ์๋ค
- โฃ DELETE ์์ฒญ์ ์์ฒญ ๋ฐ๋๋ฅผ ํฌํจํด๋ฒ๋ฆฐ๋ค
- โค ์ด๋ฏธ ์ญ์ ๋ ๋ฆฌ์์ค๋ฅผ ์ฌ์ญ์ ํ์ ๋์ ๋์ ํ์ธ์ ์์ด๋ฒ๋ฆฐ๋ค
- 08. DELETE API ํ ์คํธ์ ๋ฒ ์คํธ ํ๋ํฐ์ค
- 09. ์์ฃผ ๋ฌป๋ ์ง๋ฌธ๏ผFAQ๏ผ
- 10. ์ ๋ฆฌ
00. API ํ ์คํธ์ DELETE ์์ฒญ์ ๊ธฐ๋ณธ
DELETE ์์ฒญ์ ใ๋ฆฌ์์ค๋ฅผ ์ญ์ ํ๋ใ ์กฐ์์ ๋๋ค. GET์ด๋ POST์ ๋นํด ์ฌํํ์ง๋ง ์ญ์ ํ ๋ฆฌ์์ค์ ์ํ ํ์ธ์ด ์ค์ํฉ๋๋ค.
| ํ์ธ ํญ๋ชฉ | ๋ด์ฉ | ์ |
|---|---|---|
| ์ํ ์ฝ๋ | ์ญ์ ์ฑ๊ณต ์ 200 ๋๋ 204๊ฐ ๋ฐํ๋๋๊ฐ | 200 OK / 204 No Content |
| ์ญ์ ํ ํ์ธ | ์ญ์ ํ GETํ๋ฉด 404๊ฐ ๋ฐํ๋๋๊ฐ | 404 Not Found |
| ์กด์ฌํ์ง ์๋ ๋ฆฌ์์ค | ์กด์ฌํ์ง ์๋ ID๋ฅผ ์ญ์ ํ๋ ค ํ์ ๋ ์ ์ ํ ์ค๋ฅ๊ฐ ๋ฐํ๋๋๊ฐ | 404 Not Found |
| ์๋ต ๋ฐ๋ | 204์ ๊ฒฝ์ฐ ๋ฐ๋๊ฐ ๋น์ด์๋๊ฐ | {} ๋๋ ๋น ๊ฐ |
๐ก ํฌ์ธํธ๏ผDELETE ํ ์คํธ๋ ใ์ญ์ ํ ์ ์์๋คใ๋ฟ๋ง ์๋๋ผ ใ์ญ์ ํ ์ ๊ทผํ ์ ์๊ฒ ๋์๋คใ๊น์ง ํ์ธํจ์ผ๋ก์จ ์ง์ ํ ์๋ฏธ์ ํ ์คํธ๊ฐ ๋ฉ๋๋ค.
01. pytest + requests์ API ํ ์คํธ ํ๊ฒฝ
์์ง ํ๊ฒฝ ๊ตฌ์ถ์ด ์ ๋ ๋ถ์ ๋จผ์ ์ค์นํด์ฃผ์ธ์.
pip install requests pytest pytest-html์ด๋ฒ ํ
์คํธ ๋์์ ๋ฌด๋ฃ ๋ชฉ๏ผmock๏ผ API JSONPlaceholder ์
๋๋ค.
DELETE https://jsonplaceholder.typicode.com/users/1๐ก ํฌ์ธํธ๏ผJSONPlaceholder๋ ๋ชฉ API์ด๋ฏ๋ก DELETE๋ฅผ ์คํํด๋ ์ค์ ๋ฐ์ดํฐ๋ ์ญ์ ๋์ง ์์ต๋๋ค. ๊ทธ ๋๋ฌธ์ ์ญ์ ํ GETํด๋ 200์ด ๋ฐํ๋๋ ๊ฒฝ์ฐ๊ฐ ์์ต๋๋ค. ์ค์ API์์๋ ์ญ์ ํ GET์์ 404๊ฐ ๋ฐํ๋๋ ๊ฒ์ ๊ธฐ๋ํ์ฌ ํ ์คํธ๋ฅผ ์์ฑํ๋ ๊ฒฝ์ฐ๊ฐ ๋ง์ต๋๋ค.
02. Python์ผ๋ก API DELETE ํ ์คํธ๋ฅผ ์์ฑํ๋ ๋ฐฉ๋ฒ
๊ธฐ๋ณธ์ ์ธ DELETE ํ ์คํธ๏ผ200 ํ์ธ๏ผ
DELETE ์์ฒญ์ ๋ณด๋ด๊ณ 200์ด ๋ฐํ๋๋ ๊ฒ์ ํ์ธํฉ๋๋ค.
import requests
BASE_URL = "https://jsonplaceholder.typicode.com"
def test_delete_user_status_code():
"""TC01: DELETE๋ก ์ญ์ ์ ์ํ ์ฝ๋ 200์ด ๋ฐํ๋์ด์ผ ํ๋ค"""
response = requests.delete(f"{BASE_URL}/users/1")
assert response.status_code == 200, \
f"๊ธฐ๋๊ฐ: 200, ์ค์ ๊ฐ: {response.status_code}"
print(f"\nโ
TC01 PASS | ์ํ ์ฝ๋: {response.status_code}")raise_for_status()๋ก 4xx/5xx๋ฅผ ํ์คํ ๊ฒ์ง
def test_delete_user_raise_for_status():
"""TC02: 4xx/5xx ์ค๋ฅ ์ ์์ธ๊ฐ ๋ฐ์ํด์ผ ํ๋ค"""
response = requests.delete(f"{BASE_URL}/users/1")
response.raise_for_status()
assert response.status_code == 200
print(f"\nโ
TC02 PASS | raise_for_status() ์ ์ ํต๊ณผ")๐ก ํฌ์ธํธ๏ผraise_for_status() ๋ฅผ ์ฌ์ฉํ๋ฉด 4xx/5xx๋ฅผ ์์ธ๋ก ๊ฒ์งํ ์ ์์ต๋๋ค. ํ์ง๋ง API ํ
์คํธ์์๋ ์๋์ ์ผ๋ก 4xx/5xx๋ฅผ ํ์ธํ๋ ์ผ์ด์ค๋ ์์ผ๋ฏ๋ก, status_code์ assert์ ์ฌ์ฉ ๊ตฌ๋ถํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค.
์๋ต ๋ฐ๋ ํ์ธ
DELETE์ ์๋ต ๋ฐ๋๊ฐ ๋น์ด์๊ฑฐ๋ ๋น JSON์ด ๋ฐํ๋๋ ๊ฒ์ ํ์ธํฉ๋๋ค.
def test_delete_user_response_body():
"""TC03: DELETE์ ์๋ต ๋ฐ๋๊ฐ ๋น ๊ฐ ๋๋ ๋น JSON์ด์ด์ผ ํ๋ค"""
response = requests.delete(f"{BASE_URL}/users/1")
response.raise_for_status()
# 204 No Content์ผ ๋ json()์ ํธ์ถํ๋ฉด JSONDecodeError๊ฐ ๋๋ฏ๋ก ๋ถ๊ธฐ
if response.status_code == 204:
body = None
else:
body = response.json()
assert body in [None, {}], \
f"์ญ์ ํ ์๋ต ๋ฐ๋๋ ๋น ๊ฐ์ด ๊ธฐ๋๊ฐ: {body}"
print(f"\nโ
TC03 PASS | ์๋ต ๋ฐ๋: {body}")๐ก ํฌ์ธํธ๏ผDELETE์ ์๋ต ๋ฐ๋๋ API ์ค๊ณ์ ๋ฐ๋ผ ๋ค๋ฆ ๋๋ค. ๋น JSON `{}`ใป๋น ๋ฌธ์์ดใป204 No Content๏ผ๋ฐ๋ ์์๏ผ์ ํจํด์ด ์์ต๋๋ค. ๋ฐ๋์ ์ํ ์ฝ๋๋ฅผ ํ์ธํ๊ณ ๋์ json()์ ํธ์ถํ์ธ์.
03. API ํ ์คํธ DELETE ํ ์ํ ํ์ธ
์ญ์ ํ ์คํธ์์ ๊ฐ์ฅ ์ค์ํ ๊ฒ์ด ใ์ญ์ ํ ๋ฆฌ์์ค์ ์ ๊ทผํ ์ ์๊ฒ ๋์ด ์๋๊ฐใ์ ํ์ธ์ ๋๋ค.
์ญ์ ํ GETํ๋ฉด 404๊ฐ ๋ฐํ๋๋ ๊ฒ์ ํ์ธ
def test_delete_then_get_returns_404():
"""TC04: ์ญ์ ํ GETํ๋ฉด 404๊ฐ ๋ฐํ๋์ด์ผ ํ๋ค"""
# Step1: ๋ฆฌ์์ค๋ฅผ ์ญ์
delete_response = requests.delete(f"{BASE_URL}/users/1")
assert delete_response.status_code == 200, "์ญ์ ๊ฐ ์คํจํ์ต๋๋ค"
# Step2: ์ญ์ ํ GETํด๋ณธ๋ค
get_response = requests.get(f"{BASE_URL}/users/1")
# JSONPlaceholder๋ ๋ชฉ์ด๋ฏ๋ก 200์ด ๋ฐํ๋๋ ๊ฒฝ์ฐ๋ ์๋ค
# ์ค์ API์์๋ 404๊ฐ ๋ฐํ๋๋ ๊ฒ์ ๊ฒ์ฆํ๋ค
assert get_response.status_code in [200, 404], \
f"์ญ์ ํ GET์ 404๊ฐ ๊ธฐ๋๊ฐ: {get_response.status_code}"
print(f"\nโ
TC04 PASS | ์ญ์ ํ GET ์ํ: {get_response.status_code}")๐ก ํฌ์ธํธ๏ผ์ญ์ ํ 404๊ฐ ๋ฐํ๋๋ ๊ฒ์ ํ์ธ์ 2์คํ ํ ์คํธ๏ผDELETEโGET๏ผ๋ก ์คํํฉ๋๋ค. ์ด๊ฒ์ด DELETE ํ ์คํธ์์ ๊ฐ์ฅ ์ค์ํ ๊ฒ์ฆ์ ๋๋ค.
04. API ํ ์คํธ DELETE ์ด์๊ณ ํจํด
์กด์ฌํ์ง ์๋ ๋ฆฌ์์ค ์ญ์ ๏ผ404 ํ์ธ๏ผ
def test_delete_nonexistent_user():
"""TC05: ์กด์ฌํ์ง ์๋ ๋ฆฌ์์ค ์ญ์ ์ 404๊ฐ ๋ฐํ๋์ด์ผ ํ๋ค"""
response = requests.delete(f"{BASE_URL}/users/99999")
# JSONPlaceholder๋ ๋ชฉ์ด๋ฏ๋ก 200์ด ๋ฐํ๋๋ ๊ฒฝ์ฐ๋ ์๋ค
# ์ค์ API์์๋ 404๊ฐ ๊ธฐ๋๋จ
assert response.status_code in [200, 404], \
f"์์ ๋ฐ์ ์ํ ์ฝ๋: {response.status_code}"
print(f"\nโ
TC05 PASS | ์กด์ฌํ์ง ์๋ ๋ฆฌ์์ค ์ญ์ : {response.status_code}")โ ๏ธ ์ฃผ์๏ผJSONPlaceholder๋ ๋ชฉ API์ด๋ฏ๋ก ์กด์ฌํ์ง ์๋ ID์๋ 200์ ๋ฐํํ๋ ๊ฒฝ์ฐ๊ฐ ์์ต๋๋ค. ์ค์ API์์๋ 404๊ฐ ๋ฐํ๋๋ ๊ฒ์ ๊ฒ์ฆํด์ฃผ์ธ์.
200๊ณผ 204 ๋ ๋ค์ ๋์ํ ํ ์คํธ
def test_delete_user_accepts_200_or_204():
"""TC06: ์ญ์ ์ฑ๊ณต ์ 200 ๋๋ 204๊ฐ ๋ฐํ๋์ด์ผ ํ๋ค"""
response = requests.delete(f"{BASE_URL}/users/1")
# REST API ๊ด์ต: ์ญ์ ์ฑ๊ณต์ 200 ๋๋ 204
assert response.status_code in [200, 204], \
f"์ญ์ ์ฑ๊ณต ์ 200 ๋๋ 204๊ฐ ๊ธฐ๋๊ฐ: {response.status_code}"
print(f"\nโ
TC06 PASS | ์ํ ์ฝ๋: {response.status_code}")๐ก ํฌ์ธํธ๏ผ์ญ์ ์ฑ๊ณต ์ ์ํ ์ฝ๋๋ API ์ค๊ณ์ ๋ฐ๋ผ 200 ๋๋ 204๊ฐ ๋ฐํ๋ฉ๋๋ค. ๋ ๋ค์ ๋์ํ ์ ์๋ ์์ฑ๋ฒ์ผ๋ก ํด๋๋ฉด ๋ฒ์ฉ์ฑ์ด ๋์์ง๋๋ค.
05. API ํ ์คํธ DELETE ํค๋ ๊ฒ์ฆ
def test_delete_user_header():
"""TC07: Content-Type์ด JSON์ด์ด์ผ ํ๋ค๏ผ204 ์ด์ธ์ ๊ฒฝ์ฐ๏ผ"""
response = requests.delete(f"{BASE_URL}/users/1")
response.raise_for_status()
# 204 No Content๋ Content-Type ํค๋๊ฐ ์กด์ฌํ์ง ์๋ ๊ฒฝ์ฐ๊ฐ ์๋ค
if response.status_code != 204:
content_type = response.headers.get("Content-Type", "")
assert "application/json" in content_type, \
f"์์ ๋ฐ์ Content-Type: {content_type}"
print(f"\nโ
TC07 PASS | Content-Type: {content_type}")
else:
print(f"\nโ
TC07 PASS | 204 No Content์ด๋ฏ๋ก Content-Type ์ฒดํฌ ์คํต")06. DELETE ํ ์คํธ ์ ์ฒด ์ฝ๋
"""
DELETE API Test
Target: JSONPlaceholder (https://jsonplaceholder.typicode.com)
Framework: Python + requests + pytest
"""
import requests
BASE_URL = "https://jsonplaceholder.typicode.com"
def test_delete_user_status_code():
"""TC01: DELETE๋ก ์ญ์ ์ ์ํ ์ฝ๋ 200์ด ๋ฐํ๋์ด์ผ ํ๋ค"""
response = requests.delete(f"{BASE_URL}/users/1")
assert response.status_code == 200, \
f"๊ธฐ๋๊ฐ: 200, ์ค์ ๊ฐ: {response.status_code}"
print(f"\nโ
TC01 PASS | status: {response.status_code}")
def test_delete_user_raise_for_status():
"""TC02: 4xx/5xx ์ค๋ฅ ์ ์์ธ๊ฐ ๋ฐ์ํด์ผ ํ๋ค"""
response = requests.delete(f"{BASE_URL}/users/1")
response.raise_for_status()
assert response.status_code == 200
print(f"\nโ
TC02 PASS | raise_for_status() ์ ์ ํต๊ณผ")
def test_delete_user_response_body():
"""TC03: DELETE์ ์๋ต ๋ฐ๋๊ฐ ๋น ๊ฐ ๋๋ ๋น JSON์ด์ด์ผ ํ๋ค"""
response = requests.delete(f"{BASE_URL}/users/1")
response.raise_for_status()
if response.status_code == 204:
body = None
else:
body = response.json()
assert body in [None, {}]
print(f"\nโ
TC03 PASS | body: {body}")
def test_delete_then_get_returns_404():
"""TC04: ์ญ์ ํ GETํ๋ฉด 404๊ฐ ๋ฐํ๋์ด์ผ ํ๋ค"""
delete_response = requests.delete(f"{BASE_URL}/users/1")
assert delete_response.status_code == 200
get_response = requests.get(f"{BASE_URL}/users/1")
assert get_response.status_code in [200, 404]
print(f"\nโ
TC04 PASS | ์ญ์ ํ GET ์ํ: {get_response.status_code}")
def test_delete_nonexistent_user():
"""TC05: ์กด์ฌํ์ง ์๋ ๋ฆฌ์์ค ์ญ์ ์ 404๊ฐ ๋ฐํ๋์ด์ผ ํ๋ค"""
response = requests.delete(f"{BASE_URL}/users/99999")
assert response.status_code in [200, 404]
print(f"\nโ
TC05 PASS | status: {response.status_code}")
def test_delete_user_accepts_200_or_204():
"""TC06: ์ญ์ ์ฑ๊ณต ์ 200 ๋๋ 204๊ฐ ๋ฐํ๋์ด์ผ ํ๋ค"""
response = requests.delete(f"{BASE_URL}/users/1")
assert response.status_code in [200, 204]
print(f"\nโ
TC06 PASS | status: {response.status_code}")
def test_delete_user_header():
"""TC07: Content-Type์ด JSON์ด์ด์ผ ํ๋ค๏ผ204 ์ด์ธ์ ๊ฒฝ์ฐ๏ผ"""
response = requests.delete(f"{BASE_URL}/users/1")
response.raise_for_status()
if response.status_code != 204:
content_type = response.headers.get("Content-Type", "")
assert "application/json" in content_type
print(f"\nโ
TC07 PASS | Content-Type: {content_type}")
else:
print(f"\nโ
TC07 PASS | 204์ด๋ฏ๋ก ์คํต")์คํ ์ปค๋งจ๋
pytest test_delete_api.py -v -s์คํ ๊ฒฐ๊ณผ ์ํ
test_delete_api.py::test_delete_user_status_code PASSED
test_delete_api.py::test_delete_user_raise_for_status PASSED
test_delete_api.py::test_delete_user_response_body PASSED
test_delete_api.py::test_delete_then_get_returns_404 PASSED
test_delete_api.py::test_delete_nonexistent_user PASSED
test_delete_api.py::test_delete_user_accepts_200_or_204 PASSED
test_delete_api.py::test_delete_user_header PASSED
7 passed in 3.56s โ
07. ์์ฃผ ๊ฒช๋ ๋ฌธ์ & ํด๊ฒฐ๋ฒ
๊ตฌํ ์ค ์ค์ ๋ก ๊ฒช์๋ ๋ฌธ์ ๋ค์ ์ ๋ฆฌํ์ต๋๋ค. ๊ฐ์ ๊ณณ์์ ๋งํ๋ ๋ถ๋ค๊ป ๋์์ด ๋๋ฉด ์ข๊ฒ ์ต๋๋ค.
โ ์ญ์ ์ฑ๊ณต์ด 200์ธ์ง 204์ธ์ง ํท๊ฐ๋ฆฐ๋ค
DELETE ์ฑ๊ณต ์๋ต์ด 200์ธ์ง 204์ธ์ง ํท๊ฐ๋ ธ์ต๋๋ค. API ์ค๊ณ์ ๋ฐ๋ผ ๋ค๋ฆ ๋๋ค.
# โ ๊ณ ์ ์ผ๋ก 200๋ง์ ๊ธฐ๋ํด๋ฒ๋ฆฐ๋ค
assert response.status_code == 200
# โ
200๊ณผ 204 ๋ ๋ค๋ฅผ ํ์ฉํ๋ค
assert response.status_code in [200, 204]
# 200 OK โ ์๋ต ๋ฐ๋ ์์๏ผ์ญ์ ํ ๋ฆฌ์์ค ์ ๋ณด ๋ฑ๏ผ
# 204 No Content โ ์๋ต ๋ฐ๋ ์์๏ผ์ฌํํ ์ญ์ ํ์ธ๏ผ๐ก ํฌ์ธํธ๏ผํ ์คํธ๋ฅผ ์์ฑํ๊ธฐ ์ ์ API ๋ฌธ์์์ ๊ธฐ๋ํ๋ ์ํ ์ฝ๋๋ฅผ ํ์ธํ์ธ์. JSONPlaceholder๋ 200์ ๋ฐํํฉ๋๋ค.
โก 204์ผ ๋ response.json()์์ ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ค
204 No Content์ ์๋ต์์ response.json() ์ ํธ์ถํ๋๋ ๋ฐ๋๊ฐ ๋น์ด์์ด ์ค๋ฅ๊ฐ ๋ฐ์ํ์ต๋๋ค.
# โ 204์ผ ๋ json()์ ํธ์ถํ๋ฉด ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ค
body = response.json() # JSONDecodeError!
# โ
์ํ ์ฝ๋๋ก ๋ถ๊ธฐํ๋ค
if response.status_code == 204:
print("์๋ต ๋ฐ๋ ์์๏ผ204 No Content๏ผ")
else:
body = response.json()
print(f"์๋ต ๋ฐ๋: {body}")โ ๏ธ ์ฃผ์๏ผ204 No Content๋ ์๋ต ๋ฐ๋๊ฐ ์กด์ฌํ์ง ์์ต๋๋ค. ์ํ ์ฝ๋๋ฅผ ํ์ธํ๊ณ ๋์ json()์ ํธ์ถํ๋๋ก ํ์ธ์.
โข ๋ชฉ API์์ ์ญ์ ํ 404๋ฅผ ํ์ธํ ์ ์๋ค
JSONPlaceholder์์ DELETE ํ GETํด๋ 200์ด ๋ฐํ๋์ด๋ฒ๋ ค ์ญ์ ํ 404 ํ์ธ์ด ๋ถ๊ฐ๋ฅํ์ต๋๋ค.
# JSONPlaceholder๋ ๋ชฉ์ด๋ฏ๋ก
# DELETE ํ GETํด๋ 200์ด ๋ฐํ๋์ด๋ฒ๋ฆฐ๋ค
requests.delete(f"{BASE_URL}/users/1")
response = requests.get(f"{BASE_URL}/users/1")
print(response.status_code) # โ 200๏ผ์ค์ API์์๋ 404๊ฐ ๊ธฐ๋๋จ๏ผ๐ก ํฌ์ธํธ๏ผ์ญ์ ํ 404 ํ์ธ์ ์ค์ ๋ก ๋ฐ์ดํฐ๊ฐ ์ญ์ ๋๋ API๋ก ์ํํด์ผ ํฉ๋๋ค. Restful Booker๋ ์ง์ ๋ง๋ API๋ก ๊ฒ์ฆํ์ธ์.
โฃ DELETE ์์ฒญ์ ์์ฒญ ๋ฐ๋๋ฅผ ํฌํจํด๋ฒ๋ฆฐ๋ค
DELETE ์์ฒญ์ ์์ฒญ ๋ฐ๋๋ฅผ ํฌํจํ๋ ค ํ์ง๋ง, ๋๋ถ๋ถ์ REST API์์ DELETE๋ URL๋ก ์ญ์ ๋์์ ์ง์ ํ๋ฏ๋ก ์ผ๋ฐ์ ์ผ๋ก ๋ฐ๋๋ ๋ถํ์ํฉ๋๋ค.
# โ DELETE์ ๋ฐ๋๋ฅผ ํฌํจํ๋ ๊ฒ์ ๋๋ถ๋ถ์ REST API์์ ์ผ๋ฐ์ ์ด์ง ์๋ค
response = requests.delete(url, json={"id": 1})
# โ
DELETE๋ URL๋ง์ผ๋ก ์ง์ ํ๋ ๊ฒ์ด ๊ธฐ๋ณธ
response = requests.delete(f"{BASE_URL}/users/1")๐ก ํฌ์ธํธ๏ผDELETE๋ ํต์ URL ํ๋ผ๋ฏธํฐ๋ก ์ญ์ ๋์์ ์ง์ ํ๋ฏ๋ก ๋๋ถ๋ถ์ REST API์์๋ ์์ฒญ ๋ฐ๋๋ ๋ถํ์ํฉ๋๋ค. ๋ค๋ง Elasticsearch ๋ฑ ์ผ๋ถ API์์๋ ์ญ์ ์กฐ๊ฑด์ ๋ฐ๋๋ก ๋ณด๋ด๋ ์ค๊ณ๋ ์์ต๋๋ค. API ๋ฌธ์๋ก ํ์ธํ์ธ์.
โค ์ด๋ฏธ ์ญ์ ๋ ๋ฆฌ์์ค๋ฅผ ์ฌ์ญ์ ํ์ ๋์ ๋์ ํ์ธ์ ์์ด๋ฒ๋ฆฐ๋ค
ํ ๋ฒ ์ญ์ ํ ๋ฆฌ์์ค๋ฅผ ๋ค์ ์ญ์ ํ๋ ค๊ณ ํ์ ๋ ์ด๋ค ์๋ต์ด ๋ฐํ๋๋์ง ํ์ธํ๋ ๊ฒ์ ์์์ต๋๋ค.
# ์ญ์ ๋ ๋ฆฌ์์ค๋ฅผ ์ฌ์ญ์ ํ ๊ฒฝ์ฐ
response1 = requests.delete(f"{BASE_URL}/users/1") # 1ํ์งธ: ์ฑ๊ณต๏ผ200๏ผ
response2 = requests.delete(f"{BASE_URL}/users/1") # 2ํ์งธ: ์ด๋ฏธ ์กด์ฌํ์ง ์์
assert response1.status_code == 200
# ์ค์ API์์๋ 2ํ์งธ๋ 404๊ฐ ๊ธฐ๋๋จ
assert response2.status_code in [200, 404]๐ก ํฌ์ธํธ๏ผ์ฌ์ญ์ ํ ์คํธ๋ ์ค์ API์์์ ๊ฒ์ฆ์ด ํ์ํฉ๋๋ค. ๋ชฉ API์์๋ ํ์ธํ ์ ์์ต๋๋ค.
08. DELETE API ํ ์คํธ์ ๋ฒ ์คํธ ํ๋ํฐ์ค
DELETE API ํ ์คํธ์์๋ ๋ค์ 3๊ฐ์ง๋ฅผ ํ์ธํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค.
| ํ์ธ ํญ๋ชฉ | ๋ด์ฉ | ์ค์๋ |
|---|---|---|
| โ ์ํ ์ฝ๋ ํ์ธ | ์ญ์ ์ฑ๊ณต ์ 200 ๋๋ 204๊ฐ ๋ฐํ๋ ๊ฒ | โญโญโญ ํ์ |
| โก ์ญ์ ํ 404 ํ์ธ | ์ญ์ ํ GETํ๋ฉด 404๊ฐ ๋ฐํ๋ ๊ฒ | โญโญโญ ์ค์ |
| โข ์ด์๊ณ ํ์ธ | ์กด์ฌํ์ง ์๋ ๋ฆฌ์์ค ์ญ์ ์ ์ ์ ํ ์ค๋ฅ๊ฐ ๋ฐํ๋ ๊ฒ | โญโญ ๊ถ์ฅ |
์ด 3๊ฐ์ง๋ฅผ ํ์ธํจ์ผ๋ก์จ DELETE API์ ํ์ง์ ๋์ ์์ค์ผ๋ก ๋ณด์ฆํ ์ ์์ต๋๋ค. ํนํ ์ญ์ ํ GETํ๋ฉด 404๊ฐ ๋ฐํ๋๋ ๊ฒ์ ํ์ธ์ ๋จ์ํ ใ์ญ์ ํ ์ ์์๋คใ๋ฟ๋ง ์๋๋ผ ใ์ญ์ ํ ์ ๊ทผํ ์ ์๊ฒ ๋์๋คใ๊น์ง ๊ฒ์ฆํ๋ฏ๋ก ์ค๋ฌด์์๋ ๋ฐ๋์ ์ค์ํ์ธ์.
๐ก ํฌ์ธํธ๏ผGETใปPOSTใปPUT/PATCHใปDELETE์ 4์ข ๋ฅ๋ฅผ ๊ตฌํํจ์ผ๋ก์จ CRUD ์ ์กฐ์์ ์ปค๋ฒํ ์์ ํ API ํ ์คํธ ์ค์ํธ๊ฐ ์์ฑ๋ฉ๋๋ค. ์ด๊ฒ์ ํฌํธํด๋ฆฌ์ค๋ก์๋ ๋งค์ฐ ๊ฐ๋ ฅํ ์ดํ์ด ๋ฉ๋๋ค.
09. ์์ฃผ ๋ฌป๋ ์ง๋ฌธ๏ผFAQ๏ผ
Q. DELETE ํ
์คํธ์์ ์ต์ํ ํ์ธํด์ผ ํ ๊ฒ์ ๋ฌด์์ธ๊ฐ์๏ผ
A. ์ต์ํ ใ์ํ ์ฝ๋๊ฐ 200 ๋๋ 204์ธ ๊ฒใ1๊ฐ์ง์
๋๋ค. ์ฌ์ ๊ฐ ์๋ค๋ฉด ใ์ญ์ ํ GETํ๋ฉด 404๊ฐ ๋ฐํ๋๋ ๊ฒใ๋ ์ถ๊ฐํ๋ฉด ์ค๋ฌด ์์ค์ ํ
์คํธ๊ฐ ๋ฉ๋๋ค.
Q. DELETE ์ํ ์ฝ๋๋ 200๊ณผ 204 ์ด๋ ๊ฒ์ด ์ฌ๋ฐ๋ฅธ๊ฐ์๏ผ
A. ๋ ๋ค ์ฌ๋ฐ๋ฆ
๋๋ค. API ์ค๊ณ์ ๋ฐ๋ผ ๋ค๋ฆ
๋๋ค. ์ญ์ ํ ๋ฆฌ์์ค ์ ๋ณด๋ฅผ ๋ฐํํ๋ ๊ฒฝ์ฐ๋ 200, ์๋ฌด๊ฒ๋ ๋ฐํํ์ง ์๋ ๊ฒฝ์ฐ๋ 204๊ฐ ์ฌ์ฉ๋๋ ๊ฒฝ์ฐ๊ฐ ๋ง์ต๋๋ค. ํ
์คํธ๋ฅผ ์์ฑํ๊ธฐ ์ ์ API ๋ฌธ์๋ก ํ์ธํ์ธ์.
Q. DELETE ์์ฒญ์ ์์ฒญ ๋ฐ๋๊ฐ ํ์ํ๊ฐ์๏ผ
A. ์ผ๋ฐ์ ์ผ๋ก ๋ถํ์ํฉ๋๋ค. DELETE๋ URL ๊ฒฝ๋ก ํ๋ผ๋ฏธํฐ๋ก ์ญ์ ๋์์ ์ง์ ํฉ๋๋ค๏ผ์๏ผ/users/1๏ผ. ๋ค๋ง ์ผ๋ถ API์์๋ ์ญ์ ์ด์ ๋ฑ์ ๋ฐ๋๋ก ๋ณด๋ด๋ ๊ฒฝ์ฐ๋ ์์ต๋๋ค. API ๋ฌธ์๋ก ํ์ธํ์ธ์.
Q. ์ญ์ ํ 404 ํ์ธ์ ์ด๋ API๋ก ์ํํด๋ณผ ์ ์๋์๏ผ
A. JSONPlaceholder๋ ๋ชฉ API์ด๋ฏ๋ก ์ญ์ ํ 404 ํ์ธ์ด ๋ถ๊ฐ๋ฅํฉ๋๋ค. reqres.in ์ด๋ ์ง์ ๋ง๋ API, ๋๋ Restful Booker์ ์์ฝ ์ญ์ ์๋ํฌ์ธํธ๋ก ์ํํด๋ณผ ์ ์์ต๋๋ค.
Q. CRUD ํ
์คํธ๋ฅผ ์ ๋ถ ์์ฑํ๋ฉด ๋ช ๊ฑด์ด ๋๋์๏ผ
A. ์ด๋ฒ ์๋ฆฌ์ฆ์์ ๊ตฌํํ ํ
์คํธ ์ผ์ด์ค๋ GET๏ผ9๊ฑด๏ผใปPOST๏ผ9๊ฑด๏ผใปPUT/PATCH๏ผ9๊ฑด๏ผใปDELETE๏ผ7๊ฑด๏ผ์ ํฉ๊ณ 34๊ฑด์
๋๋ค. ์ด ์ ๋๋ฉด ใCRUD๊ฐ ์ ๋ถ ๊ฐ๋ฅํ๋คใ๋ ํฌํธํด๋ฆฌ์ค๋ก์ ์ถฉ๋ถํ ์ดํ์ด ๋ฉ๋๋ค.
10. ์ ๋ฆฌ
Python์ผ๋ก API DELETE ํ ์คํธ๋ฅผ ๊ตฌํํ๋ ๊ฒฝ์ฐ, pytest์ requests๋ฅผ ์ฌ์ฉํด์ ์ํ ์ฝ๋์ ์ญ์ ํ ์ํ ํ์ธ์ด ์ค๋ฌด์ ๊ธฐ๋ณธ์ ๋๋ค. DELETE๋ ์ฌํํ ํ ์คํธ์ด์ง๋ง ์ญ์ ํ 404๊ฐ ๋ฐํ๋๋ ๊ฒ๊น์ง ํ์ธํจ์ผ๋ก์จ ์์ ํ CRUD ํ ์คํธ๊ฐ ๋ฉ๋๋ค.
์ด ๊ธ์์๋ pytest์ requests๋ฅผ ์ฌ์ฉํ API DELETE ํ ์คํธ ๊ตฌํ ๋ฐฉ๋ฒ์ ํด์คํ์ต๋๋ค.
| ํ ์คํธ ์ผ์ด์ค | ๋ด์ฉ |
|---|---|
| TC01 | DELETE๋ก ์ญ์ ์ ์ํ ์ฝ๋ 200์ด ๋ฐํ๋์ด์ผ ํ๋ค |
| TC02 | raise_for_status()๋ก 4xx/5xx๋ฅผ ๊ฒ์ง |
| TC03 | DELETE์ ์๋ต ๋ฐ๋๊ฐ ๋น ๊ฐ ๋๋ ๋น JSON์ด์ด์ผ ํ๋ค |
| TC04 | ์ญ์ ํ GETํ๋ฉด 404๊ฐ ๋ฐํ๋์ด์ผ ํ๋ค |
| TC05 | ์กด์ฌํ์ง ์๋ ๋ฆฌ์์ค ์ญ์ ์ 404๊ฐ ๋ฐํ๋์ด์ผ ํ๋ค |
| TC06 | ์ญ์ ์ฑ๊ณต ์ 200 ๋๋ 204๊ฐ ๋ฐํ๋์ด์ผ ํ๋ค |
| TC07 | Content-Type์ด JSON์ด์ด์ผ ํ๋ค๏ผ204 ์ด์ธ์ ๊ฒฝ์ฐ๏ผ |
GETใปPOSTใปPUT/PATCHใปDELETE ์ ๋ถ ๊ตฌํํ์ฌ CRUD ์ ์กฐ์์ API ํ ์คํธ๊ฐ ์์ฑ๋์์ต๋๋ค. ๋ค์ ๊ธ์์๋ ์๋ฆฌ์ฆ ๋ง๋ฌด๋ฆฌ๋ก ์ค๋ฌด์์์ API ํ ์คํธ ์ค๊ณ ๋ฐฉ๋ฒ์ ํด์คํฉ๋๋ค.

