From d55a84f83f78950251f531f4f79a695335b90dff Mon Sep 17 00:00:00 2001 From: "Marcus A." Date: Sun, 5 Apr 2026 23:45:12 +0000 Subject: [PATCH] Add pytest test suite for Shopping List API\n\nTest coverage:\n- Root endpoint\n- Product CRUD\n- List CRUD\n- List items flow (add, update, delete, cascade)\n\nUse: pytest test_main.py\n\nOperation: shopping-list-api-2026-04-05\nWI3: Testing and validation --- test_main.py | 132 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 test_main.py diff --git a/test_main.py b/test_main.py new file mode 100644 index 0000000..bb99326 --- /dev/null +++ b/test_main.py @@ -0,0 +1,132 @@ +import pytest +from fastapi.testclient import TestClient +from main import app, init_db +import sqlite3 +import os + +client = TestClient(app) + +def setup_module(module): + # Use an in-memory database for tests + os.environ["DB_PATH"] = ":memory:" + init_db() + +def test_root(): + r = client.get("/") + assert r.status_code == 200 + assert r.json() == {"message": "Shopping List API"} + +def test_product_crud(): + # Create + r = client.post("/products", json={"name": "Paper Plates", "sku": "PP-001"}) + assert r.status_code == 201 + product = r.json() + assert product["name"] == "Paper Plates" + assert product["sku"] == "PP-001" + product_id = product["id"] + + # List + r = client.get("/products") + assert r.status_code == 200 + assert len(r.json()) >= 1 + assert any(p["id"] == product_id for p in r.json()) + + # Get + r = client.get(f"/products/{product_id}") + assert r.status_code == 200 + assert r.json()["id"] == product_id + + # Delete + r = client.delete(f"/products/{product_id}") + assert r.status_code == 200 + assert r.json()["deleted"] == product_id + + # Get deleted -> 404 + r = client.get(f"/products/{product_id}") + assert r.status_code == 404 + +def test_list_crud(): + # Create + r = client.post("/lists", json={"name": "Picnic List"}) + assert r.status_code == 201 + lst = r.json() + assert lst["name"] == "Picnic List" + list_id = lst["id"] + + # List + r = client.get("/lists") + assert r.status_code == 200 + assert any(l["id"] == list_id for l in r.json()) + + # Get empty items + r = client.get(f"/lists/{list_id}") + assert r.status_code == 200 + assert r.json()["items"] == [] + + # Delete + r = client.delete(f"/lists/{list_id}") + assert r.status_code == 200 + assert r.json()["deleted"] == list_id + +def test_list_items_flow(): + # Create two products + r1 = client.post("/products", json={"name": "Paper Plates"}) + r2 = client.post("/products", json={"name": "Bread"}) + p1 = r1.json() + p2 = r2.json() + p1_id, p2_id = p1["id"], p2["id"] + + # Create a list + r = client.post("/lists", json={"name": "Picnic List"}) + lst = r.json() + list_id = lst["id"] + + # Add items + r = client.post(f"/lists/{list_id}/items", json={"product_id": p1_id, "quantity": 2}) + assert r.status_code == 201 + item1 = r.json() + assert item1["product_id"] == p1_id + assert item1["quantity"] == 2 + + r = client.post(f"/lists/{list_id}/items", json={"product_id": p2_id, "quantity": 1}) + item2 = r.json() + assert r.status_code == 201 + assert item2["product_id"] == p2_id + assert item2["quantity"] == 1 + + # List items + r = client.get(f"/lists/{list_id}/items") + assert r.status_code == 200 + items = r.json() + assert len(items) == 2 + qty_by_prod = {i["product_id"]: i["quantity"] for i in items} + assert qty_by_prod[p1_id] == 2 + assert qty_by_prod[p2_id] == 1 + + # Get list with items + r = client.get(f"/lists/{list_id}") + assert r.status_code == 200 + data = r.json() + assert len(data["items"]) == 2 + assert any(i["product_name"] == "Paper Plates" for i in data["items"]) + + # Update quantity + r = client.patch(f"/lists/{list_id}/items/{item1['id']}", json={"quantity": 5}) + assert r.status_code == 200 + assert r.json()["quantity"] == 5 + + # Delete item + r = client.delete(f"/lists/{list_id}/items/{item2['id']}") + assert r.status_code == 200 + + # Verify item2 gone + r = client.get(f"/lists/{list_id}/items") + assert r.status_code == 200 + assert len(r.json()) == 1 + + # Delete list cascades items + r = client.delete(f"/lists/{list_id}") + assert r.status_code == 200 + + r = client.get(f"/lists/{list_id}") + assert r.status_code == 404