一起使用 pytest fixtures 和 peewee transactions
Using pytest fixtures and peewee transactions together
我正在使用 pytest
为一些使用 peewee
实现的数据库模型编写一组单元测试。我想使用数据库事务(数据库是 Postgres 数据库,如果相关的话)以便在每次测试后回滚任何数据库更改。
我有一种情况,我想在测试中使用两个装置,但让两个装置都通过 rollback
方法清理它们的数据库模型,如下所示:
@pytest.fixture
def test_model_a():
with db.transaction() as txn: # `db` is my database object
yield ModelA.create(...)
txn.rollback()
@pytest.fixture
def test_model_b():
with db.transaction() as txn: # `db` is my database object
yield ModelB.create(...)
txn.rollback()
def test_models(test_model_a, test_model_b):
# ...
这有效,但阅读 documentation for peewee
表明这是容易出错的:
If you attempt to nest transactions with peewee using the transaction()
context manager, only the outer-most transaction will be used. However if an exception occurs in a nested block, this can lead to unpredictable behavior, so it is strongly recommended that you use atomic()
.
但是,atomic()
没有提供 rollback()
方法。似乎在显式管理事务时,关键是使用最外层的 transaction()
,并在该事务中使用 savepoint()
上下文管理器。但是在我上面的测试代码中,两个固定装置都在同一个 "level" 上,可以这么说,我不知道在哪里创建事务,也不知道在哪里创建保存点。
我唯一的其他想法是使用 fixtures 被评估的顺序来决定将交易放在哪里 (which seems to be alphabetical),但这看起来确实很脆弱。
有办法实现吗?还是我的测试设计需要重新考虑?
如果你想回滚在测试中创建的所有事务,你可以有一个 fixture 来处理事务本身并让模型 fixtures 使用它:
@pytest.fixture
def transaction():
with db.transaction() as txn: # `db` is my database object
yield txn
txn.rollback()
@pytest.fixture
def test_model_a(txn):
yield ModelA.create(...)
@pytest.fixture
def test_model_b(txn):
yield ModelB.create(...)
def test_models(test_model_a, test_model_b):
# ...
这样所有模型都在同一个事务中创建并在测试结束时回滚。
如果您想 运行 针对干净的数据库进行单独测试,您可以使用 peewee 文档中指定的 Database.bind_ctx()
和 Model.bind_ctx()
方法:
http://docs.peewee-orm.com/en/latest/peewee/database.html#testing-peewee-applications
我正在使用 pytest
为一些使用 peewee
实现的数据库模型编写一组单元测试。我想使用数据库事务(数据库是 Postgres 数据库,如果相关的话)以便在每次测试后回滚任何数据库更改。
我有一种情况,我想在测试中使用两个装置,但让两个装置都通过 rollback
方法清理它们的数据库模型,如下所示:
@pytest.fixture
def test_model_a():
with db.transaction() as txn: # `db` is my database object
yield ModelA.create(...)
txn.rollback()
@pytest.fixture
def test_model_b():
with db.transaction() as txn: # `db` is my database object
yield ModelB.create(...)
txn.rollback()
def test_models(test_model_a, test_model_b):
# ...
这有效,但阅读 documentation for peewee
表明这是容易出错的:
If you attempt to nest transactions with peewee using the
transaction()
context manager, only the outer-most transaction will be used. However if an exception occurs in a nested block, this can lead to unpredictable behavior, so it is strongly recommended that you useatomic()
.
但是,atomic()
没有提供 rollback()
方法。似乎在显式管理事务时,关键是使用最外层的 transaction()
,并在该事务中使用 savepoint()
上下文管理器。但是在我上面的测试代码中,两个固定装置都在同一个 "level" 上,可以这么说,我不知道在哪里创建事务,也不知道在哪里创建保存点。
我唯一的其他想法是使用 fixtures 被评估的顺序来决定将交易放在哪里 (which seems to be alphabetical),但这看起来确实很脆弱。
有办法实现吗?还是我的测试设计需要重新考虑?
如果你想回滚在测试中创建的所有事务,你可以有一个 fixture 来处理事务本身并让模型 fixtures 使用它:
@pytest.fixture
def transaction():
with db.transaction() as txn: # `db` is my database object
yield txn
txn.rollback()
@pytest.fixture
def test_model_a(txn):
yield ModelA.create(...)
@pytest.fixture
def test_model_b(txn):
yield ModelB.create(...)
def test_models(test_model_a, test_model_b):
# ...
这样所有模型都在同一个事务中创建并在测试结束时回滚。
如果您想 运行 针对干净的数据库进行单独测试,您可以使用 peewee 文档中指定的 Database.bind_ctx()
和 Model.bind_ctx()
方法:
http://docs.peewee-orm.com/en/latest/peewee/database.html#testing-peewee-applications