我们将情况简化为以下情况:
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())
测试夹具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())
我很感激为什么pytest示例不会导致第二个测试用例的重新初始化数据库的任何观点。
答案 0 :(得分:0)
django_db_setup
的作用域是会话,因此仅在测试会话开始时运行一次。使用transaction=True
时,测试后数据库将刷新,因此django_db_setup
中添加的所有数据都将被删除。
TransactionTestCase
显然知道它正在使用事务,因此知道它需要为每个测试重新添加固定装置。
您有以下选择:
function
范围。但这可能是选择加入的,它将在事务内运行,因此在测试完成后将被删除。from unittest.mock import patch
from django.core.management import call_command
from django.db import DEFAULT_DB_ALIAS, ConnectionHandler
import pytest
_need_data_load = True
@pytest.fixture(autouse=True)
def auto_loaddata(django_db_blocker, request):
global _need_data_load
if _need_data_load:
# Use a separate DB connection to ensure we're not in a transaction.
con_h = ConnectionHandler()
try:
def_con = con_h[DEFAULT_DB_ALIAS]
# we still need to unblock the database because that's a test level
# constraint which simply monkey patches the database access methods
# in django to prevent access.
#
# Also note here we need to use the correct connection object
# rather than any default, and so I'm assuming the command
# imports `from django.db import connection` so I can swap it.
with django_db_blocker.unblock(), patch(
'path.to.your.command.modules.connection', def_con
):
call_command('loaddata')
finally:
con_h.close_all()
_need_auto_sql = False
using_transactional_db = (
'transactional_db' in request.fixturenames
or 'live_server' in request.fixturenames
)
if using_transactional_db:
# if we're using a transactional db then we will dump the whole thing
# on teardown, so need to flag that we should set it up again after.
_need_data_load = True