Flask+Pytest多测试函数运行时报SQLAlchemy实例已注册错误
Flask多测试函数下SQLAlchemy重复注册错误的解决
问题场景
采用Miguel Grinberg风格的Flask项目结构时,测试文件仅含单个测试函数时Pytest运行正常;新增第二个测试函数后执行失败。单独运行每个测试函数或合并为单个函数时均可通过,但同一测试文件中同时运行两个测试函数会触发以下错误:
RuntimeError: A 'SQLAlchemy' instance has already been registered on this Flask app. Import and use that instance instead.
报错原因
问题根源在项目根目录app/__init__.py的全局app实例定义:
- 代码提前创建了全局的
app = Flask(__name__),create_app函数复用了这个全局实例 - Pytest每个测试函数都会重新执行
appfixture,即再次调用create_app('testing') - 第二次调用
create_app时,db.init_app(app)尝试给同一个全局app实例再次注册SQLAlchemy,触发重复注册错误
解决方案
删除全局的Flask实例定义,在create_app函数内部创建全新的Flask应用实例,确保每次调用create_app都生成独立的app,避免重复注册SQLAlchemy。
修改后的app/__init__.py代码
from flask import Flask from flask_sqlalchemy import SQLAlchemy from config import config import logging import os from flask_apscheduler import APScheduler import socket db = SQLAlchemy() scheduler = APScheduler() # 移除全局的app = Flask(__name__)定义 def create_app(config_name): # 在函数内部创建独立的Flask实例 app = Flask(__name__) app.config.from_object(config[config_name]) gunicorn_logger = logging.getLogger('gunicorn.error') gunicorn_logger.setLevel(logging.DEBUG) app.logger.handlers = gunicorn_logger.handlers app.logger.setLevel(gunicorn_logger.level) db.init_app(app) # Fix to ensure only one Gunicorn worker grabs the scheduled task try: sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.bind(("127.0.0.1", 47200)) except socket.error: pass else: scheduler.init_app(app) scheduler.start() from app.responses.controllers import responses_bp app.register_blueprint(responses_bp) from app.membership.controllers import membership_bp app.register_blueprint(membership_bp) return app
额外优化建议
为保证测试独立性,建议在app fixture中添加数据库清理逻辑,避免测试间数据污染:
@pytest.fixture def app(): app = create_app('testing') with app.app_context(): # 创建测试所需数据表 db.create_all() yield app # 测试结束后清理数据 db.session.remove() db.drop_all()
内容的提问来源于stack exchange,提问作者Oh_No_nononono
相关产品推荐
相关产品推荐

