web-dev-qa-db-ja.com

pytest-djangoを実行しようとしたときに「アプリがまだロードされていません」

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.pyQuestionモデルとChoiceモデルを作成しました。

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 ================================

これまでのところ、これを修正する方法を見つけることができませんでした。テストを実行する方法について何かアイデアはありますか?

8
Kurt Peek

箱から出して、pytestpytest-Djangoがインストールされていても、Djangoデータベースについて知りません。ただし、恐れることはありません:pytest-Djangoはそれを作りますテストでDjangoデータベースにアクセスするのは簡単です Django_db pytest mark

これを試してみてください:

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
6
Franey

Django:AppRegistryNotReady() によると、_manage.py_を使用しない場合は、Django.setup()を明示的に呼び出す必要があります。 _manage.py_シェルから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デコレータはありますか?

3
Kurt Peek

pytestまたは_python setup.py test_のいずれかを使用してテストを呼び出すときに、同様の問題が発生しました。

pytest呼び出しの場合、仮想環境に_pytest-Django_をインストールすると問題が解決しました。

_python setup.py install_の場合、setup()の_pytest-Django_引数に_tests_require_を追加すると解決しました。

_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,
)
_
2

私の場合、コマンドラインまたはpytest.iniでDjango_SETTINGS_MODULEをエクスポートとして設定すると、問題が解決しました。 conftest.pyでのそのenvvarのエクスポートを無視しているようです。それがわかったら、この投稿を更新します。

ドキュメントのどこかに、Django.test.TestCaseをサブクラス化せずにテストが機能するはずだと書かれていますか? Django-pytestがDjangoアプリの読み込みに関して特別なことをしているとは思いません。したがって、クラスがTestCaseから継承し続ける場合は、次のことができるはずです。アサーション、フィクスチャなど、pytestの他のすべてを使用します。

0
MrName