使用SQLAlchemy同一SessionLocal得到不同数据,pytest测试该如何修复?
问题根因
从日志打印的会话对象地址可以确认,测试用例中注入的db和接口请求触发依赖注入生成的db是两个独立的SQLAlchemy会话实例,导致跨会话数据不可见,具体原因有两个:
flush()方法只会将会话内的变更同步到数据库的待提交事务中,没有执行commit()的前提下,变更对其他会话完全不可见- 如果你使用的是SQLite内存数据库,默认配置下每个独立连接会生成一个专属内存库,两个会话对应两个独立连接,自然互相看不到数据
修复方案
方案1:统一测试环境会话实例(推荐)
这是FastAPI+SQLAlchemy测试的标准解决方案,通过依赖覆盖让接口和测试用例共用同一个会话:
在你的pytest fixture定义文件中添加如下配置:
import pytest from fastapi.testclient import TestClient from your_app.main import app from your_app import deps @pytest.fixture(scope="function") def db(): # 生成测试用会话 test_db = SessionLocal() yield test_db # 测试结束后回滚所有变更,清理数据 test_db.rollback() test_db.close() @pytest.fixture(scope="function") def client(db): # 重写get_db依赖,接口调用时统一返回测试用会话 def override_get_db(): yield db app.dependency_overrides[deps.get_db] = override_get_db yield TestClient(app) # 测试结束后清除依赖覆盖,避免影响其他测试 app.dependency_overrides.clear()
修改后测试用例中注入的client和db会共用同一个会话,接口内的变更不需要提交就能直接在测试用例中查询到,测试结束后自动回滚,不会污染其他用例。
方案2:显式提交事务
如果不需要复用测试会话,你只需要在接口的crud.user.create操作后添加db.commit(),提交后的变更会对所有会话可见。注意使用该方案时,测试结束后你需要手动删除生成的测试数据,避免影响其他测试的执行。
方案3:SQLite内存库专属适配
如果你使用的是SQLite内存数据库,需要修改连接配置让所有连接共享同一个内存库:
SQLALCHEMY_DATABASE_URL = "sqlite:///:memory:?cache=shared"
同时需要在创建引擎时添加connect_args={"check_same_thread": False}参数,关闭SQLite的同线程检查限制。
内容的提问来源于stack exchange,提问作者Zeng Huang
相关产品推荐
相关产品推荐

