Тестирование Flask + PonyORM с Factoryboy - PullRequest
0 голосов
/ 04 февраля 2020

Какая настройка предлагается для тестирования Flask приложения, которое использует PonyORM для фиксации данных? При использовании SQLAlchemy в качестве слоя данных я делаю это с помощью фиксаторов Pytest + FactoryBoy - пакет предоставляет готовые SQLAlchemyModelFactory и хорошо работает с объектами сеанса SQLA. Мое app приспособление довольно простое, оно просто создает объект приложения, настроенный для тестирования, и возвращает его, а затем очищает сеанс в разрыве:

@pytest.fixture
def app():
    app = make_app('test')
    with app.app_context():
        db.create_all()
        yield app
        db.session.remove()
        db.drop_all()

С Pony нет вызова db.session.remove(), и я очищаю provider и schema атрибуты:

@pytest.fixture
def app():
    os.environ['FLASK_ENV'] = 'test'
    app = make_app(env='test')
    with app.app_context():
        db.create_tables()
        yield app
        db.drop_all_tables(with_all_data=True)
        db.provider = None
        db.schema = None

Но есть требование Pony, чтобы все взаимодействие с базой данных происходило в течение сеанса, поэтому все генерации объектов в тестах с фабриками должны быть обернуты в db_session() менеджер контекста Например:

with db_session():
    user = user_factory(name='Ivory Tower', password=self.default_pw)
    blog = blog_factory(name='Infernal Tendencies', user=user, active=active)
edit_url = url_for('blog.details', blog_id=blog.id)

Это утомительно, но работает. Генерация объекта в db_session() в фабричном классе приводит к тому, что субфактории не работают (например, user для blog в приведенном выше примере). Проблема в том, что каждый из этих объектов создается в своем собственном сеансе, поэтому их нельзя смешивать.

Это мой базовый класс фабрики:

from factory.base import Factory, FactoryOptions, OptionDefault

class PonyOptions(FactoryOptions):

    def _build_default_options(self):
        return super()._build_default_options() + [
            OptionDefault('db', None, inherit=True),
        ]


class PonyFactory(Factory):

    _options_class = PonyOptions

    class Meta:
        abstract = True

    @classmethod
    def _create(cls, model_class, *args, **kwargs):
        obj = model_class(*args, **kwargs)
        cls._meta.db.flush()
        return obj

Есть ли какой-нибудь лучший способ?

...