我正在构建一个使用多个数据库的Flask应用程序,因此我使用SQLAlchemy绑定。
由于我想隔离所有测试,因此我创建了session
固定装置,该固定装置开始交易并为每个测试创建scoped_session
。测试完成后,我将回滚应用于事务以再次获得初始状态。
当我只有一个数据库时,这很好用。但是,它不适用于新的绑定。在下面的示例中,我有三个测试:
User
对象(默认绑定)。Message
对象(messages
绑定)。User
和1 Message
。回滚后,我打印每个表中的行数。 User
表(默认绑定)始终被清除,但是Message
(messages
绑定)从不删除先前的行。
如何删除所有绑定的行?
import pytest
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80))
def __repr__(self):
return '<User %r>' % self.username
class Message(db.Model):
__bind_key__ = 'messages'
id = db.Column(db.Integer, primary_key=True)
message = db.Column(db.String(80))
def __repr__(self):
return '<MyBindTable %r>' % self.message
def create_app():
app = Flask(__name__)
app.config[
'SQLALCHEMY_DATABASE_URI'] = 'sqlite:///' + '/tmp/users.db'
app.config['SQLALCHEMY_BINDS'] = {
'messages': 'sqlite:///' + '/tmp/messages.db'
}
return app
@pytest.fixture(scope='session')
def test_app(request):
app = create_app()
ctx = app.app_context()
ctx.push()
def teardown():
ctx.pop()
request.addfinalizer(teardown)
return app
@pytest.fixture(scope='session')
def db_fixture(test_app, request):
db.init_app(test_app)
db.create_all()
def teardown():
db.drop_all()
request.addfinalizer(teardown)
return db
@pytest.fixture(scope='function')
def session(db_fixture, request):
connection = db_fixture.engine.connect()
transaction = connection.begin()
options = dict(bind=connection, binds={})
session = db_fixture.create_scoped_session(options=options)
db_fixture.session = session
def teardown():
transaction.rollback()
print()
print('Users:', len(User.query.all()))
print('Messages:', len(Message.query.all()))
connection.close()
session.remove()
request.addfinalizer(teardown)
return session
def test_two_users(session):
admin = User(username='user1')
guest = User(username='user2')
session.add(admin)
session.add(guest)
session.commit()
users = User.query.all()
assert len(users) == 2
def test_two_my_bind_table(session):
message1 = Message(message='message1')
message2 = Message(message='message2')
session.add(message1)
session.add(message2)
session.commit()
messages = Message.query.all()
assert len(messages) == 2
def test_both_tables(session):
admin = User(username='user3')
row_bind = Message(message='message2')
session.add(admin)
session.add(row_bind)
session.commit()
messages = Message.query.all()
users = User.query.all()
assert len(users) == 1
assert len(messages) == 1 # <-- It fails: len(messages) is 3
# OUTPUT:
# test.py::test_two_users PASSED
# Users: 0
# Messages: 0
#
# test.py::test_two_my_bind_table PASSED
# Users: 0
# Messages: 2 # <-- This should be 0
#
# test.py::test_both_tables FAILED
# Users: 0
# Messages: 3 # <-- This should be 0