Какая настройка предлагается для тестирования 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
Есть ли какой-нибудь лучший способ?