[英]Create distinct SQLAlchemy sessions between integration test (Pytest) and Flask application
I have flask application (RESTful API backend) that uses flask-sqlalchemy lib.我有使用flask-sqlalchemy lib的flask应用程序(RESTful API后端)。 The integration test uses Pytest with fixtures, some create records for test purposes.集成测试使用带有夹具的 Pytest,一些创建用于测试目的的记录。 The problem is that when testing scenario that's expected to raise unique constraint failure at the database level, the records created for test via fixtures all got rolled back, causing other tests to fail with error sqlalchemy.exc.InvalidRequestError: This Session's transaction has been rolled back due to a previous exception during flush. To begin a new transaction with this Session, first issue Session.rollback(). Original exception was: (sqlite3.IntegrityError) UNIQUE constraint failed: my_table.field1
问题是,当测试预期在数据库级别引发唯一约束失败的场景时,通过夹具为测试创建的记录全部回滚,导致其他测试失败,错误为sqlalchemy.exc.InvalidRequestError: This Session's transaction has been rolled back due to a previous exception during flush. To begin a new transaction with this Session, first issue Session.rollback(). Original exception was: (sqlite3.IntegrityError) UNIQUE constraint failed: my_table.field1
sqlalchemy.exc.InvalidRequestError: This Session's transaction has been rolled back due to a previous exception during flush. To begin a new transaction with this Session, first issue Session.rollback(). Original exception was: (sqlite3.IntegrityError) UNIQUE constraint failed: my_table.field1
sqlalchemy.exc.InvalidRequestError: This Session's transaction has been rolled back due to a previous exception during flush. To begin a new transaction with this Session, first issue Session.rollback(). Original exception was: (sqlite3.IntegrityError) UNIQUE constraint failed: my_table.field1
. sqlalchemy.exc.InvalidRequestError: This Session's transaction has been rolled back due to a previous exception during flush. To begin a new transaction with this Session, first issue Session.rollback(). Original exception was: (sqlite3.IntegrityError) UNIQUE constraint failed: my_table.field1
。
How do I go about creating distinct SQLAlchemy session for testing so that test records can be committed to DB and not impacted by errors that happen inside Flask request lifecycle?我如何着手创建不同的 SQLAlchemy 会话进行测试,以便测试记录可以提交到数据库,而不受 Flask 请求生命周期内发生的错误的影响?
### globals.py ###
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
### app.py ###
from sqlalchemy.exc import IntegrityError
from .globals import db
def handle_unique_constraint(error):
return {"msg": "Duplicate"}, 409
def create_app(connection_string):
app = Flask(__name__)
app.register_error_handler(IntegrityError, handle_unique_constraint)
app.config['SQLALCHEMY_DATABASE_URI'] = connection_string
# register API blueprint ...
# e.g. create new user record, done like this:
#
# db.session.add(User(**{'email': path_param}))
# db.session.commit()
db.init_app(app)
return app
### conftest.py ###
from my_package.app import create_app
from my_package.globals import db as app_db
from my_package.models.user import User
@fixture(scope='session')
def app(request):
app = create_app('https://localhost')
app.debug = True
with app.app_context():
yield app
@fixture(scope='session')
def db(app):
app_db.create_all()
return app_db
@fixture(scope='session')
def client(app):
with app.test_client() as client:
yield client
@fixture(scope='function')
def test_user(db):
user = User(**{'email': generate_random()})
db.session.add(user)
db.session.commit()
db.session.refresh(user)
### test_user.py ###
# This test passses
def test_repeat_email(client, test_user):
resp = client.post('/users/emails/{}'.format(test_user.email))
assert resp.status_code == 409
# This test errors out during setting up test_user fixture
# with aforementioned error message
def test_good_email(client, test_user): # <- this
resp = client.post('/users/emails/{}'.format('unique@example.com'))
assert resp.status_code == 201
You have to implement a setUp
and a tearDown
.你必须实现一个setUp
和一个tearDown
。
When running a tests the setUp
will be run at the start of each test.运行测试时, setUp
将在每个测试开始时运行。 The tearDown
will be run at the end of each one. tearDown
将在每个结束时运行。
In the setUp
you will: initialize the database在setUp
你会:初始化数据库
In the tearnDown
you will: close db connections, remove items created ...在tearnDown
您将:关闭数据库连接,删除创建的项目...
I'm not familiar to pytest
.我对pytest
不熟悉。 According to this and this .根据这个和这个。
Before the yield
it's the setUp
part and after it's the tearDown
.在yield
之前是setUp
部分,之后是tearDown
。
You should have something like this :你应该有这样的东西:
@fixture(scope='session')
def app(request):
app = create_app('https://localhost')
app.debug = True
ctx = app.app_context()
ctx.push()
yield app
ctx.pop()
@fixture(scope='session')
def db(app):
app_db.create_all()
yield app_db
app_db.drop_all()
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.