在Flask-SQLAlchemy中隔离py.test数据库会话 [英] Isolating py.test DB sessions in Flask-SQLAlchemy
问题描述
我编写了一个最小的完整示例来突出显示问题,注意 test_user_schema1()
和 test_user_schema2()
是相同的。 code> test_db.py
from models import User
def test_user_schema1(session):
person_name ='Fran Clan'
uu = User(name = person_name)
session.add(uu)
session.commit()
assert uu.id == 1
assert uu.name == person_name
def test_user_schema2(session):
person_name ='Stan Clan'
uu = User(name = person_name)
session.add(uu)
session.commit()
assert uu.id == 1
assert uu .name == person_name
如果db在我的测试之间是真正的隔离,那么这两个测试都应该通过。然而,最后一次测试总是失败,因为我还没有找到一个方法来使db会话正确回滚。
conftest.py
使用以下关于我在中看到的,但是这个夹具代码打破了,因为它显然不干'b
$ b
@ pytest.yield_fixture(scope ='function')
def session (app,db):
connection = db.engine.connect()
transaction = connection.begin()
#options = dict(bind = connection,binds = { })
options = dict(bind = connection)
session = db.create_scoped_session(options = options)
yield session
#
transaction.rollback()
connection.close()
session.remove()
就这个问题而言,我建立了 a gist ,其中包含所有需要重现的内容;你可以用 git clone克隆https://gist.github.com/34fa8d274fc4be240933.git
。
I我使用下列软件包...
Flask == 0.10.1
Flask-Bootstrap == 3.3.0.1
Flask-Migrate == 1.3.0
Flask-Moment == 0.4.0
Flask-RESTful == 0.3.1
Flask-Script == 2.0.5
Flask-SQLAlchemy == 2.0
Flask-WTF == 0.11
itsdangerous == 0.24
pytest == 2.6.4
Werkzeug == 0.10.1
两个问题:
- 为什么现状被破坏?
- 我怎样才能解决这个问题?
解决方案
据 所以 2。 将夹具的范围更改为 顺便说一句,如果你使用内存中的sqlite数据库,你不需要删除数据库文件,它会更快: I'm trying to build a Flask app with Flask-SQLAlchemy; I use pytest to test the DB. One of the problems seems to be creating isolated DB sessions between different tests. I cooked up a minimal, complete example to highlight the problem, note that Filename: If the db is truly isolated between my tests, both tests should pass. However, the last test always fails, because I haven't found a way to make db sessions rollback correctly. For the purposes of this question, I built a gist, which contains all you need to reproduce it; you can clone it with I am using the following packages...
commit()
用于提交当前事务。它总是事先发送flush()以将剩余的状态清除到数据库。这与自动刷新设置无关。 ....
transaction.rollback()
在会话夹具功能不会生效,因为交易已经提交。
function
而不是 session
,这样db每次被清除。 p>
@ pytest.yield_fixture(scope ='function')
def app(request):
...
$ b $ pytest.yield_fixture(scope ='function')
def db(app,request):
...
pre $ DB $ ='sqlite://'#SQLite:内存:数据库
$ pytest.yield_fixture(scope ='function')
def db(app,request):
_db.app = app
_db .create_all()
yield _db
_db.drop_all()
test_user_schema1()
and test_user_schema2()
are the same.test_db.py
from models import User
def test_user_schema1(session):
person_name = 'Fran Clan'
uu = User(name=person_name)
session.add(uu)
session.commit()
assert uu.id==1
assert uu.name==person_name
def test_user_schema2(session):
person_name = 'Stan Clan'
uu = User(name=person_name)
session.add(uu)
session.commit()
assert uu.id==1
assert uu.name==person_name
conftest.py
uses the following based on what I saw in Alex Michael's blog post, but this fixture code breaks because it apparently doesn't isolate the db sessions between fixtures.@pytest.yield_fixture(scope='function')
def session(app, db):
connection = db.engine.connect()
transaction = connection.begin()
#options = dict(bind=connection, binds={})
options = dict(bind=connection)
session = db.create_scoped_session(options=options)
yield session
# Finalize test here
transaction.rollback()
connection.close()
session.remove()
git clone https://gist.github.com/34fa8d274fc4be240933.git
.Flask==0.10.1
Flask-Bootstrap==3.3.0.1
Flask-Migrate==1.3.0
Flask-Moment==0.4.0
Flask-RESTful==0.3.1
Flask-Script==2.0.5
Flask-SQLAlchemy==2.0
Flask-WTF==0.11
itsdangerous==0.24
pytest==2.6.4
Werkzeug==0.10.1
Two questions:
- Why is status quo broken? This same py.test fixture seemed to work for someone else.
- How can I fix this to work correctly?
1.
According to Session Basics - SQLAlchemy documentation:
commit()
is used to commit the current transaction. It always issues flush() beforehand to flush any remaining state to the database; this is independent of the "autoflush" setting. ....
So transaction.rollback()
in session fixture function does not take effect, because the transaction is already committed.
2.
Change scope of fixtures to function
instead of session
so that db is cleared every time.
@pytest.yield_fixture(scope='function')
def app(request):
...
@pytest.yield_fixture(scope='function')
def db(app, request):
...
BTW, If you use in-memory sqlite database, you don't need to delete the db files, and it will be faster:
DB_URI = 'sqlite://' # SQLite :memory: database
...
@pytest.yield_fixture(scope='function')
def db(app, request):
_db.app = app
_db.create_all()
yield _db
_db.drop_all()
这篇关于在Flask-SQLAlchemy中隔离py.test数据库会话的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!