pytest测试用例通过Alembic revision配置数据库迁移未提交问题排查
问题背景
需求为使用Alembic迁移执行自定义SQL逻辑,替代db.create_all()方法完成测试环境数据库初始化。
最初实现的pytest fixture代码如下:
@pytest.fixture(scope="session", autouse=True) def db(test_app): flask_migrate.upgrade(revision='ad1185f5b0d0') yield @pytest.fixture(scope="session", autouse=True) def create_sample_dataset(db): from tests.utils import PrePopulateDBForTest PrePopulateDBForTest().create() return
执行后出现异常:flask_migrate.upgrade()运行后变更未提交到数据库,测试运行时抛出relation "table_name" does not exist错误。
后续尝试直接调用原生Alembic接口实现,仍未生效,对应代码如下:
alembic_config = AlembicConfig('migrations/alembic.ini') alembic_config.set_main_option('sqlalchemy.url', uri) alembic_upgrade(alembic_config, 'ad1185f5b0d0')
故障原因
- 缺少Flask应用上下文:Flask-Migrate依赖激活的应用上下文读取数据库连接配置,未推入上下文时执行升级,会连接到默认的开发库而非测试库,测试逻辑连接的测试库自然不存在对应表。
- 迁移操作被测试事务回滚:大部分Flask测试套件会默认开启单测试用例事务隔离,即每个用例启动时开启事务,结束后自动回滚。如果升级操作被包裹在该类事务中,执行完成后会被回滚,无法持久化表结构。
- Alembic配置缺失:直接初始化
AlembicConfig时仅传入ini文件路径,未显式指定script_location参数时,相对路径解析错误会导致Alembic找不到迁移脚本目录,静默执行失败无明显报错。
修复方案
- 在fixture中显式推入测试应用上下文,确保迁移操作连接到正确的测试数据库实例,参考实现:
import pytest from flask_migrate import upgrade @pytest.fixture(scope="session", autouse=True) def db(test_app): # 推入应用上下文,读取测试环境数据库配置 with test_app.app_context(): upgrade(revision='ad1185f5b0d0') yield @pytest.fixture(scope="session", autouse=True) def create_sample_dataset(db, test_app): with test_app.app_context(): from tests.utils import PrePopulateDBForTest PrePopulateDBForTest().create() return
- 若使用原生Alembic接口,需补全脚本路径配置,避免相对路径解析错误:
import os from alembic.config import Config from alembic import command as alembic_command # 替换为项目migrations目录的实际绝对路径 MIGRATION_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), "../migrations")) alembic_config = Config("migrations/alembic.ini") alembic_config.set_main_option("sqlalchemy.url", test_app.config["SQLALCHEMY_DATABASE_URI"]) # 显式指定迁移脚本目录 alembic_config.set_main_option("script_location", MIGRATION_DIR) alembic_command.upgrade(alembic_config, "ad1185f5b0d0")
- 调整测试事务配置:session级别的表结构初始化阶段,暂时关闭测试框架默认的自动事务回滚逻辑,待迁移、测试数据预置完成后再开启用例级事务隔离,避免DDL语句被回滚。
排查技巧:执行upgrade语句后,在同一上下文中查询
alembic_version表,如果能查询到目标版本号,说明迁移执行成功,故障原因为测试逻辑连接的数据库实例与迁移执行实例不一致;如果查询不到版本号,说明迁移未在目标库实际执行。
内容的提问来源于stack exchange,提问作者ndx
相关产品推荐
相关产品推荐

