gpt4 book ai didi

python - pytest-django 数据库初始化似乎没有重新加载数据库

转载 作者:太空宇宙 更新时间:2023-11-03 12:03:19 24 4
gpt4 key购买 nike

我们将情况归结为以下几点:

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())

测试 fixture XXX.json 包含一个条形图。第一个测试 (test_t1) 成功。第二个测试 (test_t2) 失败。似乎 transaction=True 属性不会导致使用来自测试 fixture 的数据重新初始化数据库。

如果改为使用 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 示例没有为第二个测试用例重新初始化数据库的任何观点,我将不胜感激。

最佳答案

django_db_setup 是 session 范围的,因此只在测试 session 开始时运行一次。当使用 transaction=True 时,数据库会在每次测试(包括第一个)之后被刷新,因此添加到 django_db_setup 中的任何数据都会被删除。

TransactionTestCase 显然知道它正在使用事务并且因为它是 django 的东西它知道它需要为每个测试重新添加固定装置,但是 pytest 通常不知道 django 的需求,所以它没有办法知道它需要重新运行你的 fixture django_db_setup - 就它而言它只需要运行一次,因为它是 session 范围的。

您有以下选择:

  1. 使用一个较低范围的固定装置,可能是评论中建议的 function 范围。但这可能是选择加入,并且将在交易中运行,因此将在测试完成后删除。
  2. 编写一个智能/django 感知的 fixture ,并通过检测测试何时使用事务来知道何时需要重新填充该数据。但是您需要确保正在使用的数据库连接在事务中。我在 django 1.11 上完成了这个并且它工作正常,虽然它可能需要在升级后修复。看起来像这样:
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

关于python - pytest-django 数据库初始化似乎没有重新加载数据库,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40540044/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com