如何用SQLAlchemy创建两种pytest Session Fixture并消除代码重复?
优化SQLAlchemy pytest Fixture的代码重复问题
方案:提取公共逻辑到辅助函数
将创建和销毁数据库会话的核心逻辑抽离为独立的辅助生成器函数,再在不同作用域的fixture中复用该函数,既消除代码重复,又保留各自的作用域特性。
from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker import pytest # 统一配置数据库URL,方便后续修改 DB_URL = "sqlite:///:memory:" def _get_db_session(db_url=DB_URL): # 创建引擎和会话工厂 engine = create_engine(db_url) # 若有模型定义,可在此处添加表初始化逻辑(按需启用) # Base.metadata.create_all(bind=engine) Session = sessionmaker(bind=engine) session = Session() try: yield session finally: # 确保会话无论是否异常都会关闭,避免资源泄漏 session.close() # 函数作用域fixture:每个测试函数执行前后创建/销毁独立会话 @pytest.fixture def session_function_scope(): yield from _get_db_session() # 会话作用域fixture:整个测试会话周期内复用同一个会话 @pytest.fixture(scope="session") def session_session_scope(): yield from _get_db_session()
关键优化点说明
- 消除重复代码:核心的会话创建、销毁逻辑仅实现一次,两个fixture通过
yield from复用逻辑,降低后续维护成本。 - 修复原有代码问题:
- 补全
create_engine的闭合括号(原有代码存在语法错误); - 将
session = Session改为session = Session(),正确创建会话实例(原有代码返回的是会话类而非可用实例); - 使用
try/finally保证会话在测试结束后一定会关闭,避免资源泄漏。
- 补全
- 提升可扩展性:后续修改数据库URL、添加表初始化逻辑时,只需在辅助函数中调整一次,所有依赖该逻辑的fixture都会同步更新。
场景匹配
session_function_scope:适配单元测试和功能测试,每个测试拥有独立会话,避免测试间的状态污染;session_session_scope:适用于初始化成本较高的场景(如集成测试),整个测试会话复用同一个会话,提升运行效率。
内容的提问来源于stack exchange,提问作者Long Nguyen
相关产品推荐
相关产品推荐

