根本原因是环境未隔离,测试误连生产库;应通过按环境加载配置(如TestingConfig设sqlite:///:memory:)、fixture封装client并调用db.session.remove()清理会话,避免数据污染。
测试数据污染正式库,根本原因不是代码写错了,而是环境没隔离——
指向了生产库,或者测试用的
实例和运行时共用了同一个连接池。
怎么让测试用内存 SQLite 而不碰真实数据库
别在
或
里硬编码数据库 URL。必须按环境加载配置,测试环境强制走
:
创建
,定义
类,设置
函数接收配置名(如
),调用
确保
在测试 client 初始化前已生效,否则
还是会连错库
注意:
是单连接独占的,每次
都得在同一个
实例上做;多个测试并行跑会冲突,得加
级 fixture 控制生命周期。
为什么 db.session.remove() 比 db.drop_all() 更安全
会删表结构,但测试中常需要保留 schema 只清数据;而
是 SQLAlchemy 的会话清理机制,它不删表、不重连,只丢弃当前 session 缓存并断开与当前连接的绑定。
立即学习
“
Python免费学习笔记(深入)
”;
Python 3.14.3
微软官方的 Python 扩展,是 VS Code 安装量最高的扩展(209M+)。集成 IntelliSense(通过 Pylance)、调试(通过 Python Debugger)、代码检查、格式化、重构和单元测试等功能。支持 Jupyter Notebook、虚拟环境管理和多 Python 版本切换。
下载
每个测试函数结束后立即调用
,防止 session 被下一个测试复用
如果用了 Flask-SQLAlchemy,它默认为每个请求绑定一个 session,但测试里没“请求”概念,所以必须手动清理
不要依赖
清理——它只回滚未提交的变更,对已
的数据无效
pytest fixture 怎么封装干净的测试 client
直接在测试函数里写
很容易漏掉上下文或配置。用 fixture 才能保证每次都是新 client + 新 DB 状态:
fixture 返回
前,先
建表,再
用
后的
块执行
和
(后者可选,仅当要彻底重置 schema)
避免在 fixture 里调用
——
内部已处理上下文,多套一层反而可能引发
若测试涉及登录态,别手动塞 cookie,改用
触发真实登录流程
SECRET_KEY 和 WTF_CSRF_ENABLED 必须关掉吗
不是“必须”,而是“不关就大概率失败”。CSRF token 校验依赖
和签名密钥,而测试 client 默认不维护跨请求 session:
在
中设
,省去解析 HTML 提取 token 的麻烦
仍需设置(哪怕只是
),否则
相关操作(如
)会抛
如果非要测 CSRF 行为,得用
先取页面,正则或
提取
字段,再 POST 时带上——但这属于集成测试范畴,单元测试里没必要
真正容易被忽略的是:测试运行时的
是否指向你 configure 好的那个 app 实例。工厂函数返回的 app 若没被正确传入 fixture,所有配置项(包括数据库 URL 和 SECRET_KEY)都会失效,污染问题就又回来了。
SQLALCHEMY_DATABASE_URIdbapp.pyconfig.pysqlite:///:memory:config.pyTestingConfigSQLALCHEMY_DATABASE_URI = 'sqlite:///:memory:'create_app()'testing'app.config.from_object(TestingConfig)app.config['SQLALCHEMY_DATABASE_URI']db.create_all():memory:db.create_all()dbscope='function'db.drop_all()db.session.remove()db.session.remove()db.session.rollback()commit()app.test_client()clientdb.create_all()yield clientyieldfinallydb.session.remove()db.drop_all()app.app_context()test_client()RuntimeError: working outside of application contextclient.post('/login', data={'username': 'test', 'password': '123'})sessionTestingConfigWTF_CSRF_ENABLED = FalseSECRET_KEY'test-key'sessionflask-loginRuntimeErrorclient.get()BeautifulSoupcsrf_tokencurrent_app