尝试运行 pytest-django 时出现“应用程序尚未加载”的错误。

17

Django教程中的(部分)投票应用为例,我正在尝试运行pytest-django

使用命令django-admin startproject mysite2,我创建了一个具有以下结构的项目目录:

.
├── db.sqlite3
├── manage.py
├── mysite2
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── polls
│   ├── __init__.py
│   ├── admin.py
│   ├── apps.py
│   ├── migrations
│   │   ├── 0001_initial.py
│   │   └── __init__.py
│   ├── models.py
│   ├── tests.py
│   ├── urls.py
│   └── views.py
└── pytest.ini

我的 pytest.ini 看起来像这样

[pytest]
DJANGO_SETTINGS_MODULE = mysite2.settings
python_files = tests.py test_*.py *_tests.py

按照教程,在polls/models.py中我创建了QuestionChoice模型:

import datetime

from django.db import models
from django.utils import timezone

class Question(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')

    def __str__(self):
        return self.question_text

    def was_published_recently(self):
        return self.pub_date >= timezone.now() - datetime.timedelta(days=1)

class Choice(models.Model):
    question = models.ForeignKey(Question, on_delete=models.CASCADE)
    choice_text = models.CharField(max_length=200)
    votes = models.IntegerField(default=0)

    def __str__(self):
        return self.choice_text

现在,如果我按照教程所述创建了tests.py文件,该文件基于Python内置的unittest模块。
import datetime

from django.utils import timezone
from django.test import TestCase

from .models import Question

class QuestionModelTests(TestCase):
    def test_was_published_recently_with_future_question(self):
        time = timezone.now() + datetime.timedelta(days=30)
        future_question = Question(pub_date=time)
        self.assertIs(future_question.was_published_recently(), False)

当我在命令行中运行python manage.py test时,测试失败,预期结果为:
Creating test database for alias 'default'...
System check identified no issues (0 silenced).
F
======================================================================
FAIL: test_was_published_recently_with_future_question (polls.tests.QuestionModelTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/Users/kurtpeek/Documents/Scratch/mysite2/polls/tests.py", line 23, in test_was_published_recently_with_future_question
    self.assertIs(future_question.was_published_recently(), False)
AssertionError: True is not False

----------------------------------------------------------------------
Ran 1 test in 0.001s

FAILED (failures=1)
Destroying test database for alias 'default'...

然而,如果我将测试代码更改为(尝试的)pytest 等效方式(即,无需子类化 TestCase 并具有普通断言):

def test_was_published_recently_with_future_question():
    time = timezone.now() + datetime.timedelta(days=30)
    future_question = Question(pub_date=time)
    assert future_question.was_published_recently() is False

当我运行pytest命令时,出现以下错误:
================================= test session starts ==================================
platform darwin -- Python 3.6.3, pytest-3.2.3, py-1.4.34, pluggy-0.4.0
rootdir: /Users/kurtpeek/Documents/Scratch/mysite2, inifile: pytest.ini
plugins: timeout-1.2.1
collected 0 items / 1 errors                                                            

======================================== ERRORS ========================================
___________________________ ERROR collecting polls/tests.py ____________________________
polls/tests.py:10: in <module>
    from .models import Question
polls/models.py:6: in <module>
    class Question(models.Model):
/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/django/db/models/base.py:100: in __new__
    app_config = apps.get_containing_app_config(module)
/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/django/apps/registry.py:244: in get_containing_app_config
    self.check_apps_ready()
/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/django/apps/registry.py:127: in check_apps_ready
    raise AppRegistryNotReady("Apps aren't loaded yet.")
E   django.core.exceptions.AppRegistryNotReady: Apps aren't loaded yet.
!!!!!!!!!!!!!!!!!!!!!!! Interrupted: 1 errors during collection !!!!!!!!!!!!!!!!!!!!!!!!
=============================== 1 error in 0.64 seconds ================================

到目前为止,我还没有找到解决这个问题的方法。你有什么想法可以让测试运行起来吗?


确保已设置 DJANGO_SETTINGS_MODULE。我花了很长时间才弄清楚。 - Pithikos
10个回答

12

开箱即用,pytest 不知道 Django 数据库,即使已经安装了 pytest-django 也一样。不过不用担心,pytest-django 使得你的测试可以轻松访问 Django 数据库,只需使用其 django_db pytest 标记

试一下这个:

import pytest


@pytest.mark.django_db
def test_was_published_recently_with_future_question():
    time = timezone.now() + datetime.timedelta(days=30)
    future_question = Question(pub_date=time)
    assert future_question.was_published_recently() is False

21
我遇到过类似的问题。对于任何遇到相同错误的人:请使用 pip uninstall django-pytestpip install pytest-django 代替。注意不要改变原意,使翻译更通俗易懂。 - Alex Pavlenko
1
这对我有用。令人困惑的是,也有一个django-pytest! - Yunti
@AlexPavlenko,真是个MVP。 - undefined

7

当我使用pytestpython setup.py test运行测试时,遇到了类似的问题。

对于pytest调用,将pytest-django安装在我的虚拟环境中解决了这个问题。

对于python setup.py install,在setup()tests_require参数中添加pytest-django即可解决问题。

以下是setup.py的代码片段:

TEST_REQUIREMENTS = [
    'pytest',
    'pytest-django',
    'pylint',
    'pylint_django',
    'git-pylint-commit-hook',
]

setup(
    name='foo',
    version='0.0.1',
    description='Foo package',
    author='...',
    author_email='...',
    packages=['foo'],
    install_requires=INSTALL_REQUIREMENTS,
    setup_requires=SETUP_REQUIREMENTS,
    tests_require=TEST_REQUIREMENTS,
)

在我看来,这应该是被接受的答案。pytest-django是解决问题并使Django和pytest友好相处的粘合剂。 - jaywink
是的,那对我有用。 - undefined

5
根据 Django: AppRegistryNotReady(),当不使用manage.py时,必须显式调用django.setup()。我通过在manage.py shell中运行pytest测试进行了验证。
Kurts-MacBook-Pro:mysite2 kurtpeek$ python3 manage.py shell
Python 3.6.3 (v3.6.3:2c5fed86e0, Oct  3 2017, 00:32:08) 
Type 'copyright', 'credits' or 'license' for more information
IPython 6.2.1 -- An enhanced Interactive Python. Type '?' for help.

In [1]: import pytest

In [2]: pytest.main('polls/tests.py')
================================= test session starts ==================================
platform darwin -- Python 3.6.3, pytest-3.2.3, py-1.4.34, pluggy-0.4.0
rootdir: /Users/kurtpeek/Documents/Scratch/mysite2, inifile: pytest.ini
plugins: timeout-1.2.1
collected 1 item                                                                        

polls/tests.py F

======================================= FAILURES =======================================
___________________ test_was_published_recently_with_future_question ___________________

    def test_was_published_recently_with_future_question():
        time = timezone.now() + datetime.timedelta(days=30)
        future_question = Question(pub_date=time)
>       assert future_question.was_published_recently() is False
E    assert True is False
E     +  where True = <bound method Question.was_published_recently of <Question: >>()
E     +    where <bound method Question.was_published_recently of <Question: >> = <Question: >.was_published_recently

polls/tests.py:18: AssertionError
=================================== warnings summary ===================================
None
  passing a string to pytest.main() is deprecated, pass a list of arguments instead.

-- Docs: http://doc.pytest.org/en/latest/warnings.html
========================= 1 failed, 1 warnings in 0.14 seconds =========================
Out[2]: 1

然而,这并不是一个可接受的解决方案,因为测试需要从命令行可运行。也许有其他pytest修饰符来确保所需的设置吗?


1

对我而言,在命令行或pytest.ini中将DJANGO_SETTINGS_MODULE设置为导出变量解决了问题。似乎忽略了conftest.py中该环境变量的导出。如果我找到解决方法,我会更新本帖。


0
对我而言,问题在于我忘记将pytest.ini添加到链接pytest至我的项目设置中了 - 请参见文档
# -- FILE: pytest.ini (or tox.ini)
[pytest]
DJANGO_SETTINGS_MODULE = test.settings
# -- recommended but optional:
python_files = tests.py test_*.py *_tests.py

0

只需在现有的pytest之外安装pytest-django,我也解决了这个错误:D


0

文档中是否提到测试应该在不继承django.test.TestCase的情况下工作?我不认为django-pytest在加载django应用程序方面有任何特殊处理。因此,如果你的类继续继承TestCase,你应该能够使用pytest的其他所有功能,比如断言和装置等。


1
有趣的想法,但根据文档,“更少的样板文件:无需导入unittest,创建一个带有方法的子类。只需编写常规函数作为测试。”应该是pytest-django的优势之一,因此不需要子类化。 - Kurt Peek

0
当尝试在不启动Django的情况下运行pytest时,您可能会遇到这种问题。
为了解决“Apps aren't loaded yet”错误,我进行了以下更改:
1. 创建了一个test_settings.py文件:我在我的Django应用程序的配置目录中创建了一个名为test_settings.py的新文件,并将其内容与我的settings.py相同。
2. 导入django模块并在test_settings.py中的其他模块导入和启动配置之后添加了django.setup()。
这样可以在运行测试之前初始化Django应用程序注册表和其他必要组件。
以下是test_settings.py文件的内容:
# test_settings.py

import django
... (other module imports and configurations)
django.setup()


通过添加这两行代码,解决了“应用程序尚未加载”错误,并且我能够使用pytest运行我的测试,没有任何问题。
这是我的项目结构:
.
├── Dockerfile
├── app
│   ├── config
│   │   ├── __init__.py
│   │   ├── asgi.py
│   │   ├── celery.py
│   │   ├── celery_beat_schedules.py
│   │   ├── settings.py
│   │   ├── test_settings.py
│   │   ├── urls.py
│   │   └── wsgi.py
│   ├── core
│   │   ├── __init__.py
│   │   ├── admin.py
│   │   ├── apps.py
│   │   ├── constants.py
│   │   ├── decorators.py
│   │   ├── enums.py
│   │   ├── management
│   │   │   ├── __init__.py
│   │   │   └── commands
│   │   │       ├── __init__.py
│   │   │       └── wait_for_db.py
│   │   ├── models.py
│   │   ├── services.py
│   │   ├── tests
│   │   │   ├── factories.py
│   │   │   ├── models
│   │   │   │   └── test_kr.py
│   │   │   └── views
│   │   │       └── test_search_member.py
│   │   ├── urls.py
│   │   └── views.py
│   ├── manage.py
│   ├── pytest.ini

附加说明: 确保您已安装了pytestpytest-django软件包非常重要。

0
受到上面@Peter Varshavsky的回答的启发, 我已经安装了pytest,但是调用pytest时出现了错误。 所以我安装了pytest-django,然后在根目录下创建了一个pytest.ini文件。
[pytest]
DJANGO_SETTINGS_MODULE = projectname.settings

如果你在运行命令pytest之前导出变量,它也可以正常工作。 现在,如果我调用pytest,它会成功运行。

0
在导入任何其他模型/文件之前,在conftest.py文件中进行了以下更改。
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "<MODULE_NAME>.settings")

import django
django.setup()

以上的片段帮助我解决了我的问题。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接