FastAPI单元测试中正常Payload请求返回404状态码的问题排查求助
FastAPI单元测试中正常Payload请求返回404状态码的问题排查求助
我在用pytest给FastAPI的路由写单元测试,8个测试里7个都顺利通过了,但唯独正常Payload的场景一直返回404,导致status_code == 200的断言失败。特别奇怪的是,同一个端点的其他测试(比如带缺失字段的错误Payload)能正常返回预期的400状态码,这说明路由本身是能被命中的,实在搞不懂为什么合法请求会触发404。
项目结构
├── .gitignore ├── README.md ├── app │ ├── __init__.py │ ├── main.py │ ├── pdf.py │ ├── templates.py │ ├── test_main.py ├── endpoints │ ├── statement.py │ ├── template2.py │ ├── template3.py ├── templates │ ├── statement.html │ ├── template2.html │ ├── template3.html
关键代码片段
main.py
from fastapi import FastAPI from contextlib import asynccontextmanager from typing import AsyncIterator import logging from . import templates from app.endpoints import statement # 假设lifespan函数已定义,此处省略实现 @asynccontextmanager async def lifespan(app: FastAPI) -> AsyncIterator[None]: logging.info("Service starting") yield logging.info("Service stopping") app = FastAPI( title="My App", description="Template to PDF", version="1.0.0", lifespan=lifespan, ) app.include_router(statement.router) @app.get("/", status_code=200) async def root(): return { "service": "HTML Template to PDF Converter", "status": "running", "loaded_templates": list(templates.get_all().keys()), } @app.get("/healthcheck", status_code=200) async def health_check(): return {"status": "healthy"} if __name__ == "__main__": import uvicorn uvicorn.run(app, host="127.0.0.1", port=80, log_level="info")
endpoints/statement.py
from fastapi import APIRouter, HTTPException from pydantic import BaseModel router = APIRouter(prefix="/statement", tags=["statement"]) # 定义请求Payload的Pydantic模型 class StatementPayload(BaseModel): docId: str table1: list[dict] table2: list[dict] # 其他字段省略 @router.post("/") async def generate_statement(payload: StatementPayload): # 简单的Payload校验 if not bool(payload.table1): raise HTTPException( status_code=400, detail="Table 1 missing", ) if not bool(payload.table2): raise HTTPException(status_code=400, detail="Table 2 missing") # 生成PDF的核心逻辑,此处省略 return {"status": "success", "pdf_url": "/path/to/pdf"}
test_main.py
import pytest import pytest_check as check from fastapi.testclient import TestClient from app.main import app client = TestClient(app) @pytest.fixture def good_statement(): return { "docId": "STATEMENT", "table1": [{"id": 1, "content": "test data 1"}], "table2": [{"id": 1, "content": "test data 2"}], # 其他必填字段均已正确填充 } @pytest.fixture def statement_missing_table1(): return { "docId": "STATEMENT", "table1": [], "table2": [{"id": 1, "content": "test data 2"}], # 其他字段省略 } def test_root(): response = client.get("/") expected_subset = {"service": "HTML Template to PDF Converter", "status": "running"} check.equal(response.status_code, 200) check.greater_equal(response.json().items(), expected_subset.items()) def test_healthcheck(): response = client.get("/healthcheck") assert response.status_code == 200 assert response.json() == {"status": "healthy"} def test_generate_statement_success(good_statement): # 👇 这个测试一直失败,返回404而非预期的200 response = client.post("/statement", json=good_statement) check.equal(response.status_code, 200) check.equal(response.headers["Content-Type"], "application/json") def test_generate_statement_missing_table1(statement_missing_table1): response = client.post("/statement", json=statement_missing_table1) assert response.status_code == 400 assert response.json()["detail"] == "Table 1 missing" # 其他5个测试用例均通过,此处省略
Pytest 输出
============================= test session starts ============================== collected 8 items test_main.py .......F [100%] =================================== FAILURES =================================== ____________________ test_generate_statement_success _____________________ def test_generate_statement_success(good_statement): # 👇 这个测试一直失败,返回404而非预期的200 response = client.post("/statement", json=good_statement) > check.equal(response.status_code, 200) E AssertionError: 404 != 200 test_main.py:32: AssertionError =========================== short test summary info ============================ FAILED test_main.py::test_generate_statement_success - AssertionError: 404 != 200 ========================= 1 failed, 7 passed in 0.12s ==========================
我的疑问
- 同一个
/statementPOST路由,错误Payload的测试能正确返回400,说明路由注册是有效的 - 正常Payload的请求却返回404,排除了路由不存在的可能
- 已经确认
good_statementfixture返回的Payload包含所有必填字段,格式完全符合Pydantic模型要求
有没有大佬能帮我分析下可能的原因?实在卡在这里了😭




