Reputation: 57471
Using the (partial) polls app from the Django tutorial as an example, I'm trying to get pytest-django to run.
Using the command django-admin startproject mysite2
, I've created a project directory with the following structure:
.
├── 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
My pytest.ini
looks like
[pytest]
DJANGO_SETTINGS_MODULE = mysite2.settings
python_files = tests.py test_*.py *_tests.py
Following the tutorial, in polls/models.py
I've created Question
and Choice
models:
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
Now, if I make tests.py
as described in the tutorial, which is based on Python's built-in unittest
module,
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)
and I run python manage.py test
from the command line, the test fails expected:
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'...
However, if I change the testing code to the (attempted) pytest
equivalent (that is, without having to subclass TestCase
and with ordinary assertions):
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
and run the pytest
command, I get the following error:
================================= 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 ================================
So far I haven't been able to find a way to fix this. Any ideas on how to get the test to run?
Upvotes: 20
Views: 19824
Reputation: 297
In the conftest.py file made the following changes before importing any other models / files.
import os
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "<MODULE_NAME>.settings")
import django
django.setup()
The above snippets helped me to resolve the issue for me.
Upvotes: 0
Reputation: 1917
inspired by the answer above by @Peter Varshavsky
I had pytest installed, but invoking pytest
was giving that error.
so installed pytest-django
, then i created a pytest.ini
file in the root directory with
[pytest]
DJANGO_SETTINGS_MODULE = projectname.settings
it also works if you just export the variable before running the command pytest
.
now if i invoke pytest
, it works succeussfully.
Upvotes: 0
Reputation: 1932
When trying to run pytest without starting up django, you might encounter this kind of issue.
To resolve the Apps aren't loaded yet
error, I made the following changes:
Created a test_settings.py
file: I created a new file named test_settings.py in the config directory of my Django app with the same content from my settings.py
.
Imported django
module and added django.setup()
in the test_settings.py
after other module imports and startup configurations.
This allowed me to initialize the Django app registry and other necessary components before running the tests.
Here's how the test_settings.py
file looks:
# test_settings.py
import django
... (other module imports and configurations)
django.setup()
By adding these two lines, the Apps aren't loaded yet
error was resolved, and I was able to run my tests using pytest without any issues.
Here's my project structure:
.
├── 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
Additional Note:
It's important to ensure you have the pytest
and pytest-django
packages installed.
Upvotes: 0
Reputation: 781
For me the issue was that I forgot to add pytest.ini
to link pytest
to my project settings - see the docs
# -- FILE: pytest.ini (or tox.ini)
[pytest]
DJANGO_SETTINGS_MODULE = test.settings
# -- recommended but optional:
python_files = tests.py test_*.py *_tests.py
Upvotes: 0
Reputation: 161
Just by installing pytest-django
in addition to existing pytest
, the error was gone for me as well :D
Upvotes: 0
Reputation: 448
For me, setting the DJANGO_SETTINGS_MODULE as an export on the command line or in the pytest.ini solved the problem. It seems to ignore the export of that env var in conftest.py If I figure it out I will update this post.
Upvotes: 1
Reputation: 369
I had a similar problem when invoking tests either with pytest
or python setup.py test
.
For pytest
invocation installing pytest-django
in my virtual env solved the problem.
For python setup.py install
adding pytest-django
to the tests_require
argument of setup()
solved it.
Here's the snippet of 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,
)
Upvotes: 9
Reputation: 2529
Does it say somewhere in the docs that the test should work without subclassing django.test.TestCase
? I don't think that django-pytest
does anything special in regards to loading django apps. So, if your class continues to inherit from TestCase
, you should be able to use everything else from pytest
, such as it's assertions, fixtures, etc.
Upvotes: 0
Reputation: 57471
According to Django: AppRegistryNotReady(), when not using manage.py
one must call django.setup()
explicitly. I verified this by running the pytest
test from a manage.py
shell:
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
This is not really an acceptable solution, however, as the tests need to be runnable from the command line. Are there perhaps other pytest
decorators to ensure the required setup?
Upvotes: 5
Reputation: 4354
Out of the box, pytest
doesn't know about the Django database, even with pytest-django
installed. Never fear, though: pytest-django
makes it easy for your tests to access the Django database using its django_db pytest mark.
Give this a try:
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
Upvotes: 12