将ThreadPoolExecutor与pytest-django一起使用时,为什么会得到空的django查询集?

时间:2019-07-04 02:33:41

标签: python django pytest pytest-django

我一直在尝试查找某些并发代码中的错误,并想编写一个并行运行功能的测试。我将Django与Postgres一起用作数据库,并使用pytest和pytest-django进行测试。

要运行我的功能,我正在使用ThreadPoolExecutor,只是查询数据库并返回对象数。这是django shell中的测试按预期工作:

>>> from concurrent.futures import *
>>> def count_accounts():
...     return Account.objects.all().count()
...
>>> count_accounts()
2
>>> with ThreadPoolExecutor(max_workers=1) as e:
...     future = e.submit(count_accounts)
...
>>> for f in as_completed([future]):
...     print(f.result())
...
2

但是,当我在pytest下作为测试运行时,它看起来像线程中的函数返回空查询集:

class TestCountAccounts(TestCase):
    def test_count_accounts(self):
        def count_accounts():
            return Account.objects.all().count()

        initial_result = count_accounts()  # 2
        with ThreadPoolExecutor(max_workers=1) as e:
            future = e.submit(count_accounts)

        for f in as_completed([future]):
            assert f.result() == initial_result  # 0 != 2

无论如何,我是否可以在线程内获得调用以返回正确的值/正确访问数据库?

2 个答案:

答案 0 :(得分:1)

尝试使用TransactionTestCase代替TestCaseTestCaseatomic()包装类,用atomic()包装每个测试,因此线程很可能在创建测试数据的事务之外执行。

有关两者之间区别的更多信息:http://rahmonov.me/posts/testcase-vs-transactiontestcase-in-django/

答案 1 :(得分:0)

根据上面@marquee 的回答,如果您在其中一个测试中使用 pytest 和 django 并使用 futures,则需要修改测试函数装饰器。而不仅仅是

@pytest.mark.django_db`
def test_something():
    ...

使用:

@pytest.mark.django_db(transaction=True)`
def test_something():
    ...

达到相同的结果。