带有scope ='module'的pytest-django fixture仅适用于第一次测试

时间:2017-06-28 22:33:49

标签: pytest pytest-django

通过以下夹具和测试,测试通过: 来自deals.models进口交易

@pytest.fixture(scope='function')
def myfixture(django_db_blocker):
    with django_db_blocker.unblock():
        new_deal = Deal()
        new_deal.name = 'Alice'
        new_deal.save()

@pytest.mark.django_db
def test_1(myfixture):
    print(myfixture)
    deals = Deal.objects.all()
    assert deals

@pytest.mark.django_db
def test_2(myfixture):
    print(myfixture)
    deals = Deal.objects.all()
    assert deals

结果:

============ test session starts =============
myapp/tests/pytest_test.py::test_1 PASSED
myapp/tests/pytest_test.py::test_2 PASSED

但如果我将范围更改为'module',则第二个失败:

@pytest.fixture(scope='module')
def myfixture(django_db_blocker):
    with django_db_blocker.unblock():
        load_deals()

结果:

============ test session starts =============
myapp/tests/pytest_test.py::test_1 PASSED
myapp/tests/pytest_test.py::test_2 FAILED

问题在于DB没有被持久化,因为我可以看到我可以访问创建的交易,如果我在夹具中返回它,但数据库是空的。

========= FAILURES =========
_________ test_2 _________

myfixture = id: 1, name='Alice'

    @pytest.mark.django_db
    def test_2(myfixture):
        print(myfixture)
        deals = Deal.objects.all()
>       assert deals
E       assert <QuerySet []>

如果我只运行test_2,它当然有效:

============ test session starts =============
myapp/tests/pytest_test.py::test_2 PASSED

我有很多共享相同灯具的测试,如果灯具只能运行一次因为load_deals()非常慢,那么速度会快很多。

看起来我可以重用名称django_db_setup作为fixture,而scope ='session'可以工作,但我需要根据测试运行不同的灯具。

我正在使用python 3.6.1 - pytest 3.1.2 - pytest-django 3.1.2 with mariadb 10.1

关于如何使这项工作的任何想法?

1 个答案:

答案 0 :(得分:0)

看起来不像是pytest问题。

这个对象Deal是什么?看看它的类实现。

另请查看您的数据库功能和函数load_deals()定义。

尝试添加一些日志记录,以便在调用Deal.objects

后查看Deal.objects.all()是否发生了更改

那些Deal.objects可能是generator的实例吗? (python中的生成器是disposable(仅供一次性使用)对象:

>>> g = ( i for i in range(20))
>>> g
<generator object <genexpr> at 0x101a16f10>
>>> [i for i in g]
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19]
>>> [i for i in g]  # g "has nothing to give"
[]

另请参阅此答案:Why can't I iterate twice over the same data?

@ludofet好吧,我现在看到来自django的文档 - Deal.objects.all()将返回一个QuerySet对象,该对象是来自iterable的子类 - 这是一个“单用对象”,意味着你不能在它上面迭代两次。因此,使用Deal对象的第一个测试将通过,第二个将不会在其中找到任何数据。当您的fixture具有范围“函数”时,您的测试会通过,因为fixture会为每个测试创建新的Deal对象,因此您只迭代它一次。 https://docs.djangoproject.com/en/1.11/ref/models/querysets/#all https://docs.djangoproject.com/en/1.11/ref/models/querysets/#django.db.models.query.QuerySet