You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何测试含Annotated与Depends依赖注入的FastAPI路由?解决测试问题

解决方案:FastAPI + Pytest 测试问题处理

次要问题:测试客户端弃用警告修复

直接按照警告提示修改测试客户端的创建方式,导入ASGITransport并显式指定transport参数即可消除警告:

from fastapi.testclient import TestClient
from httpx import ASGITransport
from main import app

client = TestClient(transport=ASGITransport(app=app))

主问题:Annotated[Person, Depends()]路由测试422错误解决

问题根源

当用Annotated[Person, Depends()]声明路由参数时,FastAPI会将其识别为依赖项,而非请求体参数。此时FastAPI不会自动从请求JSON中解析Person实例,若没有自定义依赖逻辑,默认的Depends()无法获取到合法的Person对象,就会返回422错误。

分场景解决方案

场景1:仅需接收请求体

如果你的需求只是接收JSON请求体并自动解析为Person模型,完全不需要加Depends(),直接使用Person作为参数即可:

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class Person(BaseModel):
    name: str
    age: int

# 正确的请求体参数写法
@app.post("/person-direct")
async def create_person(person: Person):
    return {"message": f"Hello {person.name}, age {person.age}"}

场景2:确实需要将Person作为依赖使用

如果业务逻辑要求把Person作为依赖(比如从数据库/外部服务获取、或有自定义验证逻辑),则通过**依赖覆盖(dependency override)**在测试中替换依赖返回值,同时结合参数化实现多测试用例:

步骤1:封装依赖函数

先将Person的获取逻辑封装为独立的依赖函数:

# main.py
from fastapi import FastAPI, Body
from pydantic import BaseModel
from typing import Annotated, Depends

app = FastAPI()

class Person(BaseModel):
    name: str
    age: int

def get_person() -> Person:
    # 实际场景可替换为从数据库、请求体或其他服务获取的逻辑
    return Body(...)

@app.post("/person-depends")
async def create_person_depends(person: Annotated[Person, Depends(get_person)]):
    return {"message": f"Hello {person.name}, age {person.age}"}
步骤2:测试中覆盖依赖并参数化用例

在pytest中使用app.dependency_overrides替换依赖函数,搭配@pytest.mark.parametrize实现多实例测试:

# test_main.py
import pytest
from fastapi.testclient import TestClient
from httpx import ASGITransport
from main import app, Person, get_person

client = TestClient(transport=ASGITransport(app=app))

# 自动清理依赖覆盖,避免影响其他测试
@pytest.fixture(autouse=True)
def reset_dependencies():
    yield
    app.dependency_overrides.clear()

@pytest.mark.parametrize("test_person, expected_msg", [
    (Person(name="Alice", age=25), "Hello Alice, age 25"),
    (Person(name="Bob", age=30), "Hello Bob, age 30"),
])
def test_person_depends(test_person, expected_msg):
    # 覆盖依赖,返回当前测试用的Person实例
    app.dependency_overrides[get_person] = lambda: test_person
    # 发送请求(无需传JSON,依赖已返回测试实例)
    response = client.post("/person-depends")
    assert response.status_code == 200
    assert response.json()["message"] == expected_msg

如果依赖需要从请求体获取数据,可在依赖函数中结合Body(),此时测试时正常发送JSON请求即可,确保依赖函数能正确解析。

内容的提问来源于stack exchange,提问作者mikeliux

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 00:33:25