Django和pytest之间的持久数据

时间:2019-02-27 09:23:21

标签: django pytest pytest-django pytest-describe

此问题背后的想法很容易理解,但解决起来很复杂:我需要在测试之间共享数据。

我有一个Django项目,我使用pytest-djangopytest-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,但它不起作用,每次测试后数据库仍会重置。

有没有简单的方法来实现这一目标?

谢谢。

1 个答案:

答案 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