9 / 89 · 04 API & Contract Testing with AI · AI-Generated API Test Examples← prev⊞ allnext →☰ Read as one page
2.2The Generated Test File
import pytest
import httpx
from uuid import uuid4
BASE_URL = "https://api.staging.example.com"
# ============================================================
# Fixtures
# ============================================================
@pytest.fixture
def auth_token():
"""Get a valid user-level auth token."""
return get_test_token(role="user")
@pytest.fixture
def admin_token():
"""Get a valid admin-level auth token."""
return get_test_token(role="admin")
@pytest.fixture
def seed_product(admin_token):
"""Create a product for testing, clean up afterward."""
response = httpx.post(
f"{BASE_URL}/api/v2/products",
headers={"Authorization": f"Bearer {admin_token}"},
json={"name": "Test Widget", "price": 29.99, "category": "electronics"}
)
product = response.json()
yield product
# Cleanup
httpx.delete(
f"{BASE_URL}/api/v2/products/{product['id']}",
headers={"Authorization": f"Bearer {admin_token}"}
)
# ============================================================
# GET /api/v2/products/{id}
# ============================================================
class TestGetProduct:
"""GET /api/v2/products/{id}"""
def test_get_existing_product(self, auth_token, seed_product):
"""Happy path: retrieve a known product."""
response = httpx.get(
f"{BASE_URL}/api/v2/products/{seed_product['id']}",
headers={"Authorization": f"Bearer {auth_token}"}
)
assert response.status_code == 200
body = response.json()
assert body["id"] == seed_product["id"]
assert body["name"] == seed_product["name"]
assert body["category"] in ["electronics", "clothing", "food", "other"]
assert isinstance(body["price"], (int, float))
assert body["price"] >= 0
def test_get_nonexistent_product(self, auth_token):
"""404 when product ID does not exist."""
fake_id = str(uuid4())
response = httpx.get(
f"{BASE_URL}/api/v2/products/{fake_id}",
headers={"Authorization": f"Bearer {auth_token}"}
)
assert response.status_code == 404
def test_get_product_invalid_uuid(self, auth_token):
"""400 or 422 when ID is not a valid UUID."""
response = httpx.get(
f"{BASE_URL}/api/v2/products/not-a-uuid",
headers={"Authorization": f"Bearer {auth_token}"}
)
assert response.status_code in [400, 422]
def test_get_product_no_auth(self):
"""401 when no authorization header is provided."""
response = httpx.get(f"{BASE_URL}/api/v2/products/{uuid4()}")
assert response.status_code == 401
# ============================================================
# PUT /api/v2/products/{id}
# ============================================================
class TestUpdateProduct:
"""PUT /api/v2/products/{id}"""
def test_update_product_as_admin(self, admin_token, seed_product):
"""Happy path: admin updates a product."""
response = httpx.put(
f"{BASE_URL}/api/v2/products/{seed_product['id']}",
headers={"Authorization": f"Bearer {admin_token}"},
json={"name": "Updated Widget", "price": 29.99, "category": "electronics"}
)
assert response.status_code == 200
assert response.json()["name"] == "Updated Widget"
def test_update_product_as_non_admin(self, auth_token, seed_product):
"""403 when non-admin tries to update."""
response = httpx.put(
f"{BASE_URL}/api/v2/products/{seed_product['id']}",
headers={"Authorization": f"Bearer {auth_token}"},
json={"name": "Hacked", "price": 0}
)
assert response.status_code == 403
def test_update_missing_required_name(self, admin_token, seed_product):
"""400 when required field 'name' is missing."""
response = httpx.put(
f"{BASE_URL}/api/v2/products/{seed_product['id']}",
headers={"Authorization": f"Bearer {admin_token}"},
json={"price": 10.00} # name is missing
)
assert response.status_code == 400
def test_update_missing_required_price(self, admin_token, seed_product):
"""400 when required field 'price' is missing."""
response = httpx.put(
f"{BASE_URL}/api/v2/products/{seed_product['id']}",
headers={"Authorization": f"Bearer {admin_token}"},
json={"name": "Widget"} # price is missing
)
assert response.status_code == 400
def test_update_negative_price(self, admin_token, seed_product):
"""400 when price is below minimum (0)."""
response = httpx.put(
f"{BASE_URL}/api/v2/products/{seed_product['id']}",
headers={"Authorization": f"Bearer {admin_token}"},
json={"name": "Widget", "price": -5.00}
)
assert response.status_code == 400
@pytest.mark.parametrize("name", [
"", # Below minLength (0 chars)
"A" * 201, # Above maxLength (201 chars)
])
def test_update_name_boundary(self, admin_token, seed_product, name):
"""400 when name violates length constraints."""
response = httpx.put(
f"{BASE_URL}/api/v2/products/{seed_product['id']}",
headers={"Authorization": f"Bearer {admin_token}"},
json={"name": name, "price": 10.00}
)
assert response.status_code == 400
@pytest.mark.parametrize("name", [
"A", # At minLength (1 char)
"A" * 200, # At maxLength (200 chars)
"Normal Product", # Nominal value
])
def test_update_name_valid_boundaries(self, admin_token, seed_product, name):
"""200 when name is within valid length range."""
response = httpx.put(
f"{BASE_URL}/api/v2/products/{seed_product['id']}",
headers={"Authorization": f"Bearer {admin_token}"},
json={"name": name, "price": 10.00}
)
assert response.status_code == 200
def test_update_invalid_category_enum(self, admin_token, seed_product):
"""400 when category is not in the allowed enum."""
response = httpx.put(
f"{BASE_URL}/api/v2/products/{seed_product['id']}",
headers={"Authorization": f"Bearer {admin_token}"},
json={"name": "Widget", "price": 10.00, "category": "weapons"}
)
assert response.status_code == 400
@pytest.mark.parametrize("category", [
"electronics", "clothing", "food", "other"
])
def test_update_valid_category_values(self, admin_token, seed_product, category):
"""200 for each valid enum value."""
response = httpx.put(
f"{BASE_URL}/api/v2/products/{seed_product['id']}",
headers={"Authorization": f"Bearer {admin_token}"},
json={"name": "Widget", "price": 10.00, "category": category}
)
assert response.status_code == 200
assert response.json()["category"] == category