为什么pytest测试运行后挂起,无法删除SQLAlchemy测试数据库?
问题根因
你的问题由两个关联原因导致:
- 测试结束后存在未关闭的数据库活跃会话,持有表锁导致
drop_all执行时被阻塞,进而触发进程挂起 - 关系型数据库的外键约束会阻止表删除操作,表之间存在依赖关系时直接执行
drop_all会失败
修复步骤
1. 调整session级db fixture的销毁逻辑
在执行drop_all前先清理所有活跃会话,同时根据数据库类型临时禁用外键约束,修改后的代码如下:
# 需提前导入依赖:from sqlalchemy import text @pytest.fixture(scope='session') def db(app): _db.create_all() seed_db(_db) yield _db # 清理全局scoped会话,释放连接资源 _db.session.remove() # 处理外键约束并执行表删除 with _db.engine.connect() as conn: # MySQL类数据库临时禁用外键检查 if _db.engine.dialect.name == 'mysql': conn.execute(text("SET FOREIGN_KEY_CHECKS = 0")) # SQLite类数据库临时禁用外键检查 elif _db.engine.dialect.name == 'sqlite': conn.execute(text("PRAGMA foreign_keys = OFF")) _db.drop_all() # 恢复外键检查默认配置 if _db.engine.dialect.name == 'mysql': conn.execute(text("SET FOREIGN_KEY_CHECKS = 1")) elif _db.engine.dialect.name == 'sqlite': conn.execute(text("PRAGMA foreign_keys = ON")) conn.commit()
2. 优化seed_db的会话使用逻辑
避免手动创建新会话导致会话泄漏,直接使用db绑定的全局会话操作:
def seed_db(db) -> User: user = User(username='username', password_digest=bcrypt.hash('password')) db.session.add(user) db.session.commit() return user
3. 测试配置优化(可选,进一步避免连接残留)
在TestConfig中添加以下配置,禁用数据库连接池,测试结束后自动断开所有连接:
# Flask-SQLAlchemy 2.x 版本配置 SQLALCHEMY_POOL_SIZE = 1 SQLALCHEMY_MAX_OVERFLOW = 0 SQLALCHEMY_POOL_RECYCLE = 1 # Flask-SQLAlchemy 3.x + SQLAlchemy 2.x 版本配置 SQLALCHEMY_ENGINE_OPTIONS = { "pool_size": 1, "max_overflow": 0, "pool_recycle": 1 }
验证方式
修改完成后执行单条测试用例,确认进程正常退出,同时检查测试数据库中所有表已被清理。
内容的提问来源于stack exchange,提问作者Artemiy
相关产品推荐
相关产品推荐

