Flask SQLAlchemy没有';不要让我在测试夹具中多次设置烧瓶应用程序

Flask SQLAlchemy没有';不要让我在测试夹具中多次设置烧瓶应用程序,flask,flask-sqlalchemy,Flask,Flask Sqlalchemy,我正在编写一个用于其数据库后端的应用程序 Flask应用程序是使用名为create\u app的应用程序工厂创建的 from flask import Flask def create_app(config_filename = None): app = Flask(__name__) if config_filename is None: app.config.from_pyfile('config.py', silent=True) else:

我正在编写一个用于其数据库后端的应用程序

Flask应用程序是使用名为
create\u app
的应用程序工厂创建的

from flask import Flask

def create_app(config_filename = None):
    app = Flask(__name__)
    if config_filename is None:
        app.config.from_pyfile('config.py', silent=True)
    else:
        app.config.from_mapping(config_filename)

    from .model import db
    db.init_app(app)
    db.create_all(app=app)

    return app
数据库模型由一个名为
Document
的对象组成

from flask_sqlalchemy import SQLAlchemy

db = SQLAlchemy()

class Document(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    document_uri = db.Column(db.String, nullable=False, unique=True)
我用它来做单元测试。我创建了一个名为
app\u with_documents
的pytest,它调用应用程序工厂来创建一个应用程序,并在测试运行之前将一些
Document
对象添加到数据库中,然后在单元测试完成后清空数据库

import pytest
from model import Document, db
from myapplication import create_app

@pytest.fixture
def app():
    config = {
        'SQLALCHEMY_DATABASE_URI': f"sqlite:///:memory:",
        'TESTING': True,
        'SQLALCHEMY_TRACK_MODIFICATIONS': False
    }
    app = create_app(config)
    yield app
    with app.app_context():
        db.drop_all()

@pytest.fixture
def app_with_documents(app):
    with app.app_context():
        document_1 = Document(document_uri='Document 1')
        document_2 = Document(document_uri='Document 2')
        document_3 = Document(document_uri='Document 3')
        document_4 = Document(document_uri='Document 4')
        db.session.add_all([document_1, document_2, document_3, document_4])
        db.session.commit()
    return app
我有多个使用这个夹具的单元测试

def test_unit_test_1(app_with_documents):
    ...

def test_unit_test_2(app_with_documents):
    ...
如果我运行一个单元测试,一切都会正常。如果我运行多个测试,后续的单元测试将在测试夹具设置中的
db.session.commit()
行崩溃,并显示“无这样的表:文档”

我所期望的是,每个单元测试都会获得自己的全新的、完全相同的预填充数据库,这样所有测试都会成功

(这是数据库表的问题,而不是单元测试的问题。即使我的单元测试只包含
pass
,我也会看到错误)

错误消息提到缺少表的事实使它看起来像是
create\u app
中的
db.create\u all(app=app)
在第一次单元测试运行后不会被调用。但是,我已经在调试器中验证了,正如预期的那样,每个单元测试都会调用一次此应用程序工厂函数

我对db.drop_all()的调用可能是清除数据库的错误方法。所以,我没有在内存中创建数据库,而是尝试在磁盘上创建一个数据库,然后作为测试夹具清理的一部分删除它。(这是烧瓶文档中的技术。)

这会产生相同的错误

  • 这是烧瓶和/或SQLAlchemy中的错误吗
  • 编写预先填充应用程序数据库的烧瓶测试装置的正确方法是什么

这是Flask 1.0.2、Flask SQLAlchemy 2.3.2和pytest 3.6.0,它们都是当前的最新版本。

在我的
conftest.py
中,我在我的应用程序中导入了
model.py
的内容

from model import Document, db
我使用Pycharm的pytest runner在Pycharm中运行单元测试。相反,如果我使用
python-m pytest从命令行运行测试,我会看到以下错误

ModuleNotFoundError: No module named 'model'
ERROR: could not load /Users/wmcneill/src/FlaskRestPlus/test/conftest.py
通过在
conftest.py
中完全限定导入路径,我可以从命令行运行测试

from myapplication.model import Document, db
当我这样做时,所有的单元测试都通过了。当我从Pycharm内部运行单元测试时,它们也通过了

因此,我似乎在单元测试中错误地编写了导入语句。然而,当我通过Pycharm运行这些单元测试时,没有看到关于导入的错误消息,而是启动了脚本,但随后出现了奇怪的SQL错误

我仍然没有弄明白为什么我会看到奇怪的SQL错误。大概是关于处理全局状态的方式的一些微妙之处。但是更改导入行解决了我的问题

ModuleNotFoundError: No module named 'model'
ERROR: could not load /Users/wmcneill/src/FlaskRestPlus/test/conftest.py
from myapplication.model import Document, db