抛出断言IntegrityError的单元测试后进行清理

时间:2014-03-19 13:40:45

标签: python django unit-testing testing pytest

我有一个带有"标题的Django模型" CharField(unique=True)。我有一个单元测试断言创建具有相同标题的第二个实例会抛出IntegrityError。 (我使用pytest和pytest-django。)

我有类似的东西:

class Foo(models.Model):
    title = models.CharField(unique=True)

def test_title_is_unique(db):
    Foo.objects.create(title='foo')
    with pytest.raises(IntegrityError):
        Foo.objects.create(title='foo')

这很好,除了上面的代码不包含清理代码。 pytest-django不会为您清理数据库,因此您需要在创建或保存模型实例时注册清理处理程序。像这样:

def test_title_is_unique(request, db):
    foo = Foo.objects.create(title='foo')
    request.addfinalizer(foo.delete)
    with pytest.raises(IntegrityError):
        Foo.objects.create(title='foo')

好的,没关系。但是如果第二个.create()调用错误地成功呢?我仍然希望清理该实例,但只有在(错误地)创建它时才会清理。

以下是我的决定:

def test_title_is_unique(request, db):
    foo = Foo.objects.create(title='foo')
    request.addfinalizer(foo.delete)
    try:
        with pytest.raises(IntegrityError):
            new_foo = Foo.objects.create(title='foo')
    finally:
        if 'new_foo' in locals():
            request.addfinalizer(new_foo.delete)

这并不是特别优雅或Pythonic,更不用说有一堆代码行确实不应该运行。

我如何保证第二个模型实例在创建时被清除,但跳过的圈数更少,和/或使用更少的代码行?

1 个答案:

答案 0 :(得分:2)

您不必担心清理。 pytest-django的db fixture禁用测试的事务,在一个事务中执行整个测试并在结束时回滚事务。这可确保数据库保持清洁。

如果测试需要事务,那么transactional_db fixture将启用事务(更慢)并在测试后刷新db的全部内容(非常慢)再次清理。

因此,如果没有发生清理,那么你应该在pytest-django上提交一个bug。但如果情况确实如此,我会感到惊讶,除非我错过了重要的事情。