I noticed that the helper function for loading fixtures was removed. Possibly it wasn't worth keeping around the way it was, but I was wondering if there was scope for something more useful.
The simplest thing would be a function that takes a list of fixtures and loads them. What would be even better would be to be able to use a fixtures variable within a class and have it automatically loaded as with Django's TestCases.
It does seem like a bit of a step backwards from the functionality of Django's built in testing to have to do this:
def setup_class(self):
fixtures = ['base.json', 'things.json']
for fixture in fixtures:
call_command('loaddata', fixture)
..even if it is just a few lines of code.
What do you think?
The main reason for why it was removed is that I think the use of fixtures in general should be discouraged. See Carl Meyers (Django core developer) Pycon talk for why (start watching at 16:25): http://www.youtube.com/watch?v=ickNQcNXiS4&feature=player_detailpage#t=986s
If you want to use fixtures despite of its flaws your options are:
1) Do something like the above
2) Create a helper function/mark in your project's conftest.py (should just be a couple of lines which invokes call_command)
3) Use a Django TestCase subclass with the fixtures attribute as usual
Django's testing tools makes some bad choices for testing (fixtures being one). I think we should encourage best practices wherever we have a chance to encourage better testing practices. What is a best practice and what's not is clearly not subjective, but since it is still really easy to use fixtures anyways, I don't think it is that bad to not have any support in pytest-django.
I have personally used object factories (mostly with factory_boy) instead of fixtures in my own projects with great success so far. I would really like to create a "best practices" documentation page with examples, this would be an ideally topic there.
Thoughts?
If fixtures get re-introduced it should probably be as a mark. As @pelme says this should only be a few lines.
Personally I've been manually creating the objects I need inside the test, e.g.: models.User(foo=bar) which I've found clearer so far. If you find youself constructing the same model in a number of tests you can easily create a funcarg:
def pytest_funcarg__myuser(request):
return models.User(foo=bar)
def test_foo(myuser):
assert myuser.foo == bar
Finally I'll also plug issue #11 which proposes a "models" funcarg which might make this style of creating items in the database easier.
I just realised that your own funcarg is not the most user friendly with the changes of pull request in #12. If your funcarg is loaded before the database has been initialised it will fail. This is why the admin_client funcarg needs to call django_compat.setup_databases() which you could also call. But it's not ideal.
Again, this is something that the recent funcarg/item merge solves since you can then just request the "djangodb" funcarg and it will be setup.
I am closing this issue, just to be clear, it is still possible to use Django's TestCase subclasses to use the Django fixture loading directly in the test classes.
Current best practices do not advocate fixture loading from files, so it will not be supported in pytest-django.
This works. From https://flowfx.de/blog/populate-your-django-test-database-with-pytest-fixtures/ :
import pytest
from django.core.management import call_command
@pytest.fixture(scope='session')
def django_db_setup(django_db_setup, django_db_blocker):
with django_db_blocker.unblock():
call_command('loaddata', 'potatoes_data.json')
# tests/test_models.py
def test_my_potatoes(db, django_db_setup):
# GIVEN a full database of potatoes, as provided by the django_db_setup fixture
all_my_potatoes = Potato.objects.all()
Current best practices do not advocate fixture loading from files, so it will not be supported in pytest-django.
The options for this, AFAIU, include:
For a large number of records, fixtures seem like a perfectly acceptable way to load test data into the database in Django. AFAIU, there is no plan to deprecate Django database fixtures due either to disuse or any best practices recommendations.
I think when we talk about best practices, we have to have the context of the practice.
On a staging site, it is possible that the fixtures described are previously installed from earlier generations. Whereas, sometimes this may not be the case when developing locally, or if you want to test a database from scratch.
The issue this presents is when an app with lots of different apps, which have custom calculations on the values stored in the database in order to present to a user.
In this use case, there may be data in the backend which drives these calculations, and whilst I completely agree, if I only need a user, then only create a user and that's all. Why do I need the back-end calculation in this case? Well, you don't. However, in the cases where one is creating tests that ensure the back-end calculations are correct, I would have to install each item I needed as a fixture, whereas Django would install them had they been placed in a class as is expected with the django test suite. Consider that there are use-cases for your repo that are beyond your personal projects :)
Best practice should be applied broadly and in a general fashion. I think being wary and cautious of over-applying the philosophy, else lose some of the automation conveniences that writing code satisfies.
Yeah there could be TestCase base/mixing classes with e.g. fixtureset class attrs that default to None or list config constants like ALL, or e.g. USER.
class TestCase:
fixtures = None
fixtures = ALL
fixtures = USER
fixtures = [,]
fixtures = ['book', 'author', 'etc...']
@pytest.fixture(autouse=True)
def django_fixtures_setup(django_db_setup, django_db_blocker):
with django_db_blocker.unblock():
call_command('loaddata', *['{}{}'.format(fixture, '.json') for fixture in fixtures])
Above works fine also though
Most helpful comment
This works. From https://flowfx.de/blog/populate-your-django-test-database-with-pytest-fixtures/ :