【问题标题】:Flow control and Failed: Database access not allowed, use the "django_db".... Error流控制和失败:不允许数据库访问,使用“django_db”....错误
【发布时间】:2018-09-28 12:59:34
【问题描述】:

我的芹菜任务之一遇到了一些奇怪的行为。

def run_single_test(test_name_or_decorator):
    # get dict of test names, test paths
    test_dict = get_single_test_names()

    # check to see if test is in the dict
    if test_name_or_decorator not in test_dict:
        return 'The requested test could not be found.'

    for test_name, test_path in test_dict.items():
        # if test name is valid run associated test
        if test_name == test_name_or_decorator:
            pytest.main(['-p', 'no:django','--json-report', test_path])
            report = return_test_result_json('.report.json')
            report_id = str(uuid.uuid4())
            test_run_data = TestResults.objects.create(name=report_id, data=report)

    return 'this is your test report: {}'.format(get_report(test_run_data.id))

此任务将执行 pytest.main() 命令并运行测试,但是当它使用 .create() 将 .report.json 插入 Db 时,我收到以下错误:

Failed: Database access not allowed, use the "django_db" mark, or the "db" or "transactional_db" fixtures to enable it.

现在,如果我将 for test_name.... 块中的所有功能简化并将其移至自己的功能中,一切正常:

def run_single_test_path():

    test_path = 'test_folder/test_file.py::TestClass::specific_test_name'
    pytest.main(['-p', 'no:django','--json-report', test_path])
    report = return_test_result_json('.report.json')
    report_id = str(uuid.uuid4())
    test_run_data = TestResults.objects.create(name=report_id, data=report)
    return 'this is your test report: {}'.format(get_report(test_run_data.id))

我得到了预期的回报:

"this is your test report: {'created': datetime.datetime(2018, 9, 27, 15, 51, 59, 297991, tzinfo=<UTC>), 'summary': {'total': 1, 'passed': 1}, 'exitcode': 0}"

这种行为不会发生在我使用相同 pytest.main() 和 .create() 变体的其他任务中。 另一个观察结果是,如果我首先运行此任务并引发数据库访问错误,则所有其他任务将失败并出现相同的错误。

我的工作理论是关于 for 循环或 if 的某些东西导致 .create() 吓坏了,但我完全不知道为什么。

【问题讨论】:

  • 当你将它移动到它自己的函数时,你是从 shell 还是在你的 Celery worker 上运行它?在我看来,这似乎是一个权限问题,让我认为您正在运行的两个场景之间存在设置差异
  • 目前我通过 shell_plus 从它们所在的盒子运行任务。通过导入它们,然后直接调用它们,例如: [1]: from tasks import run_single_test [2]: run_single_test('test_name')
  • 但是错误/无错误结果是在完全相同的环境中?
  • 正确。他们在同一个环境中。在这个设置中,我有 4 个 docker 容器,芹菜任务位于一个盒子上,它们正在与 psql 盒子对话。所有任务都插入到同一个数据库中。
  • 这两个文件的导入是否相同?你实施了吗? pytest-django.readthedocs.io/en/latest/…

标签: python django pytest pytest-django


【解决方案1】:

一般来说,pytest.main 不关心测试运行后留下的全局状态,因为它假定进程在测试运行完成后以返回的退出代码终止。因此,如果您在pytest.main 完成后在同一进程中运行代码,则必须小心范围内的修改。其中之一是pytest-django在django测试配置上激活的数据库拦截器;测试执行完成后它不会被停用。要停用,请在代码中明确执行:

import pytest_django

def run_single_test(test_name_or_decorator):
    ...
    pytest.main(['-p', 'no:django','--json-report', test_path])
    pytest_django.plugin._blocking_manager.unblock()

    # database access unblocked, you can run the query now
    test_run_data = TestResults.objects.create(name=report_id, data=report)

或添加一个隐式执行的运行后挂钩,例如:

# conftest.py

import pytest_django

def pytest_unconfigure(config):
    pytest_django.plugin._blocking_manager.unblock()

【讨论】:

  • 很高兴能帮上忙!
  • 我想了解造成这种情况的最初原因。这直接是我在 if 语句中包含 pytest.main() 和 .create() 的结果吗?有一次,我曾尝试创建一个 pytest 命令作为子进程,但这并没有解决问题。这还不足以制止冲突吗?
  • 这是我在 if 语句中包含 pytest.main() 和 .create() 的直接结果吗? - 是的。 有一次我曾尝试创建一个 pytest 命令作为子进程,但这并没有解决问题 - 你确定你没有将 pytestcreate 语句都放在子进程中吗?在例如调用pytest.main一个subprocess.run,等待退出码和调用create也应该是一个可行的解决方案。
  • 再次感谢您。当我在这里收到的帮助解决了我的问题时,我非常感谢,但尤其是在这种情况下,我想了解原因。
猜你喜欢
  • 2022-06-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-09
  • 2019-02-01
  • 2017-12-28
  • 2013-03-02
相关资源
最近更新 更多