SQLAlchemy не позволяет мне настраивать приложения Flask несколько раз в тестовом режиме - PullRequest
0 голосов
/ 25 мая 2018

Я пишу Flask приложение, которое использует SQLAlchemy для своей базы данных.

Приложение Flask создается с фабрикой приложений под названием create_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)

Я использую pytest для выполнения модульного тестирования.Я создаю pytest fixture с именем app_with_documents, который вызывает фабрику приложений для создания приложения и добавляет некоторые объекты 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() в настройке тестового устройства с "нет такой таблицы: документ".

    def do_execute(self, cursor, statement, parameters, context=None):
>       cursor.execute(statement, parameters)
E       sqlalchemy.exc.OperationalError: (sqlite3.OperationalError) no such table: document [SQL: 'INSERT INTO document (document_uri) VALUES (?)'] [parameters: ('Document 1',)] (Background on this error at: http://sqlalche.me/e/e3q8)

Я ожидаю, что каждый модульный тест получаетего собственная новая идентичная предварительно заполненная база данных, чтобы все тесты были успешными.

(Это проблема с таблицами базы данных, а не с модульными тестами. Я вижу ошибку, даже если мои модульные тесты состоят только из pass.)

Тот факт, что в сообщении об ошибке упоминается отсутствующая таблица, выглядит так, что db.create_all(app=app) в create_app не вызывается после первого запуска модульного теста.Однако в отладчике я убедился, что эта функция фабрики приложений вызывается один раз для каждого модульного теста, как и ожидалось.

Возможно, мой вызов db.drop_all() является неправильным способом очистки базы данных.Поэтому вместо базы данных в памяти я попытался создать ее на диске, а затем удалить как часть очистки тестового набора.(Этот метод рекомендуется в документации Flask.)

@pytest.fixture
def app():
    db_fd, db_filename = tempfile.mkstemp(suffix='.sqlite')
    config = {
        'SQLALCHEMY_DATABASE_URI': f"sqlite:///{db_filename}",
        'TESTING': True,
        'SQLALCHEMY_TRACK_MODIFICATIONS': False
    }
    yield create_app(config)
    os.close(db_fd)
    os.unlink(db_filename)

Это приводит к той же ошибке.

  • Это ошибка в Flask и /или SQLAlchemy?
  • Как правильно написать тестовые приборы Flask, которые предварительно заполняют базу данных приложения?

Это Flask 1.0.2, Flask-SQLAlchemy 2.3.2 и pytest3.6.0, которые являются текущими последними версиями.

1 Ответ

0 голосов
/ 25 мая 2018

В моем 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ошибки я сделал.Предположительно что-то тонкое в том, как обрабатывается глобальное государство.Но изменение строки импорта решает мою проблему.

...