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

为什么pytest测试运行后挂起,无法删除SQLAlchemy测试数据库?

问题根因

你的问题由两个关联原因导致:

  1. 测试结束后存在未关闭的数据库活跃会话,持有表锁导致drop_all执行时被阻塞,进而触发进程挂起
  2. 关系型数据库的外键约束会阻止表删除操作,表之间存在依赖关系时直接执行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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 21:24:02