
在 FastAPI 单元测试中,若使用 @fixture(scope="function") 注入依赖类(如 UserRepo),其内部状态(如 self.database)不会跨请求保留——因为每个 HTTP 请求都会触发新实例化,导致内存数据丢失。
在 fastapi 单元测试中,若使用 `@fixture(scope="function")` 注入依赖类(如 `userrepo`),其内部状态(如 `self.database`)不会跨请求保留——因为每个 http 请求都会触发新实例化,导致内存数据丢失。
FastAPI 的依赖注入系统在每次请求时都会重新构建被 Depends() 调用的依赖对象。这意味着:即使你将 user_repo fixture 设置为 function 作用域,并在其中注册了 MockUserRepo 类作为依赖覆盖(app.dependency_overrides[UserRepo] = MockUserRepo),FastAPI 仍会在每个请求中调用 MockUserRepo() 构造函数,创建一个全新的实例 —— 因此 self.database = [] 在每次请求中都被重置,导致 test_get_user 中前序 POST 创建的用户无法在后续 GET 请求中查到。
✅ 正确做法:将共享状态提升至 fixture 作用域内(而非实例属性)
关键在于:把可变状态(如 database 列表)定义在 fixture 函数作用域中,而非 MockUserRepo 实例内部。这样,所有由该 fixture 创建的 MockUserRepo 实例都共享同一份数据:
@fixture(scope="function")
def user_repo(app: FastAPI):
@dataclass
class User:
id: int
username: str
password: str
# ✅ 共享状态:定义在 fixture 函数体内,生命周期与 fixture 一致
database = []
class MockUserRepo:
def create_user(self, user_create_model: UserCreateModel, session: Session) -> User | None:
if session:
user = User(
id=len(database) + 1,
username=user_create_model.username,
password=user_create_model.password,
)
database.append(user)
return user
def get_user_by_id(self, id: int, session: Session) -> User | None:
if session:
return next((u for u in database if u.id == id), None)
app.dependency_overrides[UserRepo] = MockUserRepo
yield # fixture cleanup 不需要显式操作;database 随 fixture 结束自动回收
? 提示:yield 后无需 app.dependency_overrides.pop(UserRepo),因为 scope="function" 确保每次测试后 fixture 自动销毁,且 dependency_overrides 是字典引用,下次测试会重新赋值,无残留风险。
⚠️ 注意事项
- ❌ 错误写法:self.database = [] 在 __init__ 中初始化 → 每个请求新建实例,状态隔离;
- ✅ 正确写法:database = [] 在 fixture 函数体中定义 → 所有同 fixture 生命周期内的 MockUserRepo 实例共享;
- 若需跨测试用例共享(如 session scope),需额外确保线程安全(本例中单线程 pytest 默认安全);
- 此方案适用于轻量级内存模拟,真实集成测试仍应使用 pytest-asyncio + 真实 SQLite 内存数据库(sqlite:///:memory:)并配合 engine.begin() 管理事务。
通过将状态上提至 fixture 作用域,即可在单个测试函数内实现多请求间的数据一致性,精准模拟“内存数据库”行为,大幅提升 FastAPI 单元测试的可靠性与可维护性。
大量免费API接口:立即使用
涵盖生活服务API、金融科技API、企业工商API、等相关的API接口服务。免费API接口可安全、合规地连接上下游,为数据API应用能力赋能!










