Our test suite uses a custom TestRunner which has a run_suite method like so:
def run_suite(self, suite, **kwargs):
call_command('loaddata', 'foo')
call_command('loaddata', 'bar')
return super(CustomTestRunner, self).run_suite(suite, **kwargs)
The fixtures it loads are indeed so common it makes sense just to load them for every test case. For example we host multiple Sites off of our app and one of the fixtures loads a subset of those Site objects. Foreign keys to Site exist in almost all our apps so it makes sense to just load a few before the whole suite.
Although in theory I should be able to rename the fixtures to initial_data.json and have them load, that is for whatever strange reason not working. That is when I found there is no way to duct-tape over it in py.test, because the only time db access is allowed is at the function level.
Are there any plans to include a session-level fixture for db access?
Which Django version are you using?
IIRC initial_data.json is not being considered with apps that use migration in Django 1.7+.
There seems to be a workaround in a (possibly duplicate issue): https://github.com/pytest-dev/pytest-django/issues/105#issuecomment-61474664
You could also use a signal via app/management/__init__.py to work around this:
# Handle initial data in Django 1.7+.
from django.db.models import signals
from django.core.management import call_command
def load_initial_data(app_config, sender, **kwargs):
my_label = __package__.split(".")[-2]
if sender.label == my_label:
call_command('loaddata', 'initial_data.yaml', app_label=my_label)
signals.post_migrate.connect(load_initial_data, weak=False)
See also https://github.com/pytest-dev/pytest-django/pull/220#issuecomment-83310828
Aha! I had actually tried using _django_db_setup but got errors about not being allowed to access the Django DB without a marker. I suppose the _django_cursor_wrapper suppresses that issue as shown in #105. Thank you for the link @blueyed
It looks like this will allow me to use the DB in a session-level fixture, and will solve my problem. Is there any interest in making that accessible in a more user friendly way? Is this workaround unsupported and prone to break in the future?
This is something which is worked on and that will be supported by a public API. I tagged this issue with "db-configuration" which is issues related to having more options when it comes to configuring the database. I will update this issue with more information once those changes gets into master!
Here's a fixture to enable session level fixtures for db that I use. It's similar to the documented way but also does rollback at the end of the test session.
from django.db import transaction
@pytest.fixture(scope="session")
def initial_test_data(django_db_setup, django_db_blocker):
with django_db_blocker.unblock():
# Wrap in try + atomic block to do non crashing rollback
try:
with transaction.atomic():
yield
raise Exception
except Exception:
pass
@pytest.fixture(scope="session", autouse=True)
def some_initial_data(initial_test_data):
# Data added here will stay in db for the whole test session
Most helpful comment
Here's a fixture to enable session level fixtures for db that I use. It's similar to the documented way but also does rollback at the end of the test session.