pet*_*ter 5 python pytest django-unittest pytest-django
我们将情况归纳为以下几点:
import pytest
from django.core.management import call_command
from foo import bar
@pytest.fixture(scope='session')
def django_db_setup(django_db_setup, django_db_blocker):
LOGGER.info('ran call_command')
with django_db_blocker.unblock():
call_command('loaddata', 'XXX.json')
@pytest.mark.django_db(transaction=True)
def test_t1():
assert len(bar.objects.all())
@pytest.mark.django_db(transaction=True)
def test_t2():
assert len(bar.objects.all())
Run Code Online (Sandbox Code Playgroud)
测试夹具 XXX.json 包括一个栏。第一个测试 (test_t1) 成功。第二个测试 (test_t2) 失败。似乎 transaction=True 属性不会导致使用来自测试装置的数据重新初始化数据库。
如果改为使用来自 unittest 的 TransactionTestCase,则初始化发生在类中的每个测试用例之前,并且所有测试都成功。
from django.test import TransactionTestCase
from foo import bar
class TestOne(TransactionTestCase):
fixtures = ['XXX.json']
def test_tc1(self):
assert len(bar.objects.all())
def test_tc2(self):
assert len(bar.objects.all())
objs = bar.objects.all()
for bar in objs:
bar.delete()
def test_tc3(self):
assert len(bar.objects.all())
Run Code Online (Sandbox Code Playgroud)
对于为什么 pytest 示例不会为第二个测试用例重新初始化数据库的任何观点,我将不胜感激。
它django_db_setup是会话范围的,因此仅在测试会话开始时运行一次。使用时transaction=True,数据库会在每次测试(包括第一次)后刷新,因此添加的任何数据django_db_setup都会被删除。
TransactionTestCase显然知道它正在使用事务,并且因为它是 django 的东西,所以它知道它需要为每个测试重新添加固定装置,但 pytest 一般来说不知道 django 的需求,所以它没有办法知道它需要重新运行您的装置django_db_setup\xe2\x80\x93 就其而言,它只需要运行一次,因为它是会话范围的。
您有以下选择:
\nfunction评论中建议的范围。但这可能是选择加入的,并且将在事务中运行,因此在测试完成后将被删除。from unittest.mock import patch\n\nfrom django.core.management import call_command\nfrom django.db import DEFAULT_DB_ALIAS, ConnectionHandler\n\nimport pytest\n\n\n_need_data_load = True\n\n\n@pytest.fixture(autouse=True)\ndef auto_loaddata(django_db_blocker, request):\n global _need_data_load\n if _need_data_load:\n # Use a separate DB connection to ensure we\'re not in a transaction.\n con_h = ConnectionHandler()\n try:\n def_con = con_h[DEFAULT_DB_ALIAS]\n # we still need to unblock the database because that\'s a test level\n # constraint which simply monkey patches the database access methods\n # in django to prevent access.\n # \n # Also note here we need to use the correct connection object\n # rather than any default, and so I\'m assuming the command\n # imports `from django.db import connection` so I can swap it.\n with django_db_blocker.unblock(), patch(\n \'path.to.your.command.modules.connection\', def_con\n ):\n call_command(\'loaddata\')\n finally:\n con_h.close_all()\n _need_auto_sql = False\n\n using_transactional_db = (\n \'transactional_db\' in request.fixturenames\n or \'live_server\' in request.fixturenames\n )\n if using_transactional_db:\n # if we\'re using a transactional db then we will dump the whole thing\n # on teardown, so need to flag that we should set it up again after.\n _need_data_load = True\nRun Code Online (Sandbox Code Playgroud)\n