此问题背后的想法很容易理解,但解决起来很复杂:我需要在测试之间共享数据。
我有一个Django项目,我使用pytest-django和pytest-descibe来定义和运行测试。
虽然在pytest中,每次测试后都会回滚数据库,但是在“描述方式”中,通常在同一描述中的测试之间共享“上下文”。 这样可以使编写测试的可读性更高,并且运行起来更快,并且即使单个测试在两次测试之间失败也可以运行所有断言。
由于这个原因,我想在每次测试时关闭数据库回滚的默认行为,而是在运行整个describe之后执行该操作。
这是我测试的简化版本:
pytestmark = [pytest.mark.django_db]
def describe_users():
email = 'foo@example.com'
def test_create_a_user_and_it_exists():
User.objects.create(email=email)
assert User.objects.filter(email=email).exists() # Pass
def test_the_user_keeps_to_exist():
assert User.objects.filter(email=email).exists() # Fail
我尝试使用文档中建议的夹具db_access_without_rollback_and_truncate,但它不起作用,每次测试后数据库仍会重置。
有没有简单的方法来实现这一目标?
谢谢。
答案 0 :(得分:0)
首先警告:请注意,当其中一个对数据库执行意外的操作时,可能会损害后续测试用例的有效性。回滚可以确保单元测试的完整性。话虽如此,这是一个基于db_access_without_rollback_and_truncate
(简称为db_no_rollback
)的示例:
# Note: do not use pytestmark globally, because it will apply
# rollback access to everything. Instead apply it on an individual basis.
# Use this fixture wherever non-rollback database access is required.
@pytest.fixture
def db_no_rollback(request, django_db_setup, django_db_blocker):
django_db_blocker.unblock()
request.addfinalizer(django_db_blocker.restore)
# This test still uses the normal rollback.
@pytest.mark.django_db
def test_start_empty():
assert MyModel.objects.count() == 0 # PASS
# Create an object here.
def test_1(db_no_rollback):
item = MyModel.objects.create(title='ABC')
assert item.id == 1 # PASS
# It still exists here. Then we change it.
def test_2(db_no_rollback):
item = MyModel.objects.get(title='ABC')
assert item.id == 1 # PASS
item.title = 'DEF'
item.save()
# The change still persists.
def test_3(db_no_rollback):
assert MyModel.objects.get(id=1).title == 'DEF' # PASS
# This will pass, but the change won't persist.
@pytest.mark.django_db
def test_4():
item = MyModel.objects.get(title='DEF')
assert item.id == 1 # PASS
item.title = 'GHI'
item.save()
# This will fail.
@pytest.mark.django_db
def test_5():
assert MyModel.objects.get(id=1).title == 'GHI' # FAIL