Flask在线图书馆项目路由测试遇SQLAlchemy RuntimeError求助
解决Flask测试中SQLAlchemy实例未注册的RuntimeError
问题描述
开发在线图书馆项目时,编写路由测试用例,test_get_registration_form和test_get_home测试成功,但test_get_authors抛出如下错误:
RuntimeError:The current Flask app is not registered with this 'SQLAlchemy' instance. Did you forget to call 'init_app', or did you create multiple 'SQLAlchemy' instances?
相关代码
conftest.py
import pytest from flask import Flask from routes import blueprint, login_manager from flask_sqlalchemy import SQLAlchemy @pytest.fixture(scope='function') def app(): app = Flask(__name__, template_folder="../templates") app.config['SQLALCHEMY_DATABASE_URI'] = "sqlite:///" + "../instance/test_db.db" app.config['TESTING'] = True app.config['SECRET_KEY'] = 'secret_key' login_manager.init_app(app) app.register_blueprint(blueprint) return app @pytest.fixture(scope='function') def db(app): db = SQLAlchemy(app=app) return db @pytest.fixture(scope="function") def client(app): return app.test_client()
test_routes.py
def test_get_registration_form(client): response = client.get('/registration') assert response.status_code == 200 assert b'<!DOCTYPE html>' in response.data def test_get_home(client): response = client.get('/') assert response.status_code == 200 assert b'<!DOCTYPE html>' in response.data assert b'class="login-form' in response.data def test_get_authors(client): response = client.get('/authors') assert b'<!DOCTYPE html>' in response.data
routes.py
@blueprint.route('/authors', methods=["GET", "POST"]) def get_authors(): form = AuthorForm() authors = Author.query.all() return render_template("authors.html", authors=authors, form=form)
问题原因
你在测试fixture中新建了一个SQLAlchemy实例,但路由中Author.query依赖的是项目里另一个全局SQLAlchemy实例,两个实例没有关联,导致测试时Author模型找不到绑定的Flask app。
修复步骤
1. 统一项目的SQLAlchemy实例
在项目中创建一个全局的SQLAlchemy实例(通常放在models.py中),所有模型都基于这个实例创建:
# models.py from flask_sqlalchemy import SQLAlchemy db = SQLAlchemy() class Author(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(100), nullable=False)
然后在routes.py中导入这个全局实例和模型:
from models import db, Author
2. 修改测试fixture,复用全局SQLAlchemy实例
更新conftest.py,不要新建SQLAlchemy实例,而是导入全局的db,并绑定到测试app,同时创建测试用的数据库表:
# conftest.py import pytest from flask import Flask from routes import blueprint, login_manager from models import db # 导入全局db实例 @pytest.fixture(scope='function') def app(): app = Flask(__name__, template_folder="../templates") # 使用内存SQLite数据库,测试后自动销毁,避免污染本地文件 app.config['SQLALCHEMY_DATABASE_URI'] = "sqlite:///:memory:" app.config['TESTING'] = True app.config['SECRET_KEY'] = 'secret_key' login_manager.init_app(app) db.init_app(app) # 将全局db绑定到测试app app.register_blueprint(blueprint) # 在app上下文内创建所有表 with app.app_context(): db.create_all() return app @pytest.fixture(scope='function') def db_session(app): # 提供带事务回滚的数据库会话,避免测试数据互相干扰 with app.app_context(): connection = db.engine.connect() transaction = connection.begin() session = db.create_scoped_session(options={"bind": connection}) db.session = session yield session # 测试结束后回滚事务,清理数据 transaction.rollback() connection.close() session.remove() @pytest.fixture(scope="function") def client(app): return app.test_client()
3. (可选)优化测试用例,添加测试数据
如果需要验证页面是否正确显示数据,可以借助db_session fixture添加测试数据:
# test_routes.py def test_get_authors(client, db_session): # 添加测试作者 test_author = Author(name="测试作者") db_session.add(test_author) db_session.commit() response = client.get('/authors') assert response.status_code == 200 assert b'<!DOCTYPE html>' in response.data assert b'测试作者' in response.data
内容的提问来源于stack exchange,提问作者Al'kator
相关产品推荐
相关产品推荐

