Pytest patterns for Python APIs -- httpx AsyncClient, conftest fixtures, database isolation, parametrize edge cases, error response testing, auth flows, factory fixtures
99
99%
Does it follow best practices?
Impact
100%
1.23xAverage score across 5 eval scenarios
Passed
No known issues
A SaaS platform's user account service has been live for six months. The frontend team recently filed three bugs: one where the app crashed because a 404 came back as an HTML error page instead of JSON, one where the admin UI accidentally displayed password hashes in the user list, and one where the API accepted malformed JSON silently. The backend team wants tests that would have caught all three of these before they reached production.
You have been asked to write a thorough test suite for the /users resource. The tests need to go beyond verifying that the happy paths return 200 — they must verify error responses are proper JSON with the expected structure, that the response body on success contains the right fields, and that sensitive information is never exposed.
Produce the following files:
tests/conftest.py — shared fixturestests/test_users.py — the full test suitepyproject.toml — pytest configurationThe following files are provided as inputs. Extract them before beginning.
=============== FILE: app/main.py =============== from fastapi import FastAPI, HTTPException from pydantic import BaseModel from typing import List, Optional import hashlib
app = FastAPI()
_users: List[dict] = [] _next_id = 1
def hash_password(password: str) -> str: return hashlib.sha256(password.encode()).hexdigest()
class UserCreate(BaseModel): email: str name: str password: str
class UserUpdate(BaseModel): name: Optional[str] = None
@app.post("/api/users", status_code=201) async def create_user(body: UserCreate): global _next_id for u in _users: if u["email"] == body.email: raise HTTPException(status_code=409, detail="Email already taken") user = { "id": _next_id, "email": body.email, "name": body.name, "password_hash": hash_password(body.password), } _users.append(user) _next_id += 1 # Return without password_hash return {"data": {"id": user["id"], "email": user["email"], "name": user["name"]}}
@app.get("/api/users") async def list_users(): return {"data": [{"id": u["id"], "email": u["email"], "name": u["name"]} for u in _users]}
@app.get("/api/users/{user_id}") async def get_user(user_id: int): for u in _users: if u["id"] == user_id: return {"data": {"id": u["id"], "email": u["email"], "name": u["name"]}} raise HTTPException(status_code=404, detail="User not found")
@app.delete("/api/users/{user_id}", status_code=204) async def delete_user(user_id: int): global _users for u in _users: if u["id"] == user_id: _users = [x for x in _users if x["id"] != user_id] return raise HTTPException(status_code=404, detail="User not found")
@app.patch("/api/users/{user_id}") async def update_user(user_id: int, body: UserUpdate): for u in _users: if u["id"] == user_id: if body.name is not None: u["name"] = body.name return {"data": {"id": u["id"], "email": u["email"], "name": u["name"]}} raise HTTPException(status_code=404, detail="User not found")