57

I'm trying to start writing unit tests for django and I'm having some questions about fixtures:

I made a fixture of my whole project db (not certain application) and I want to load it for each test, because it looks like loading only the fixture for certain app won't be enough.

I'd like to have the fixture stored in /proj_folder/fixtures/proj_fixture.json.

I've set the FIXTURE_DIRS = ('/fixtures/',) in my settings.py. Then in my testcase I'm trying

fixtures = ['proj_fixture.json']

but my fixtures don't load. How can this be solved? How to add the place for searching fixtures? In general, is it ok to load the fixture for the whole test_db for each test in each app (if it's quite small)? Thanks!

djvg
  • 11,722
  • 5
  • 72
  • 103
gleb.pitsevich
  • 1,269
  • 2
  • 12
  • 18
  • Maybe you can use a relative path? Like `["../../fixtures/proj_fixture.json"]`. – Felix Kling Mar 18 '10 at 14:44
  • I tried, but it didn't work.. Django searches for fixtures only in the proj_folder/app_folder/fixtures – gleb.pitsevich Mar 18 '10 at 14:51
  • 2
    For those finding this later... here are the docs: https://docs.djangoproject.com/en/2.0/topics/testing/tools/#fixture-loading -- The specific issue here appears to me to be that the OP provided value for `FIXTURE_DIRS` appears to be an absolute path, when perhaps it was meant to be a relative path from the project root. – anonymous coward Jul 09 '18 at 19:38
  • 1
    [TestCase fixture loading docs](https://docs.djangoproject.com/en/stable/topics/testing/tools/#fixture-loading) – djvg Jun 10 '21 at 14:20

9 Answers9

116

I've specified path relative to project root in the TestCase like so:

from django.test import TestCase

class MyTestCase(TestCase):
    fixtures = ['/myapp/fixtures/dump.json',]
    ...

and it worked without using FIXTURE_DIRS

Evgeny
  • 10,698
  • 9
  • 60
  • 70
  • 2
    Don't know why this answer didn't receive more love. It's THE correct answer... You shouldn't have to worry about an absolute fixture path. – Cerin Mar 20 '12 at 14:50
  • 20
    My config may be different but it didn't work until I removed the first `/` character. – Mikhail Sep 14 '13 at 00:40
  • 1
    If you're testing locally in one app, it seems to be working to say `dump.json`, because Django automatically looks up the fixtures folder. – Dave Halter Sep 16 '13 at 06:27
  • FIXTURE_DIRS is not necessary. os.path.join('/a/b','/c') -> '/c'; so it works when there is no leading slash. – Wes Turner Jul 25 '16 at 09:36
  • Related documentation: https://docs.djangoproject.com/en/dev/topics/testing/tools/#fixture-loading – Joe Sadoski Jan 21 '22 at 16:24
34

Good practice is using PROJECT_ROOT variable in your settings.py:

import os.path
PROJECT_ROOT = os.path.dirname(os.path.realpath(__file__))
FIXTURE_DIRS = (os.path.join(PROJECT_ROOT, 'fixtures'),)
Leonid Shvechikov
  • 3,927
  • 2
  • 17
  • 14
32

Do you really have a folder /fixtures/ on your hard disk?

You probably intended to use:

FIXTURE_DIRS = ('/path/to/proj_folder/fixtures/',)
Ben James
  • 121,135
  • 26
  • 193
  • 155
  • 2
    I believe by default django looks for app/fixtures because `manage.py loaddata fixture.json` will work without the `FIXTURE_DIRS` variable being set. – markwalker_ Aug 21 '13 at 10:00
20

Instead of creating fixures folder and placing fixtures in them (in every app), a better and neater way to handle this would be to put all fixtures in one folder at the project level and load them.

from django.core.management import call_command

class TestMachin(TestCase):

    def setUp(self):
        # Load fixtures
        call_command('loaddata', 'fixtures/myfixture', verbosity=0)

Invoking call_command is equivalent to running :

 manage.py loaddata /path/to/fixtures 
Armance
  • 5,350
  • 14
  • 57
  • 80
  • 1
    I agree with this, just wanted to point out that the [docs](https://docs.djangoproject.com/en/3.0/howto/initial-data/#where-django-finds-fixture-files) do imply putting them in separate per-app fixtures dirs. Perhaps that is the source of this problem in the first place (it was for me). – user5359531 Jan 07 '20 at 19:56
  • If I have use `setUp` to load my fixtures, do I need to use `tearDown` after? – ron_g Mar 29 '22 at 06:29
9

Saying you have a project named hello_django with api app.

Following are steps to create fixtures for it:

  1. Optional step: create fixture file from database: python manage.py dumpdata --format=json > api/fixtures/testdata.json
  2. Create test directory: api/tests
  3. Create empty file __init__.py in api/tests
  4. Create test file: test_fixtures.py
from django.test import TestCase

class FixturesTestCase(TestCase):
  fixtures = ['api/api/fixtures/testdata.json']
  def test_it(self):
    # implement your test here
  1. Run the test to load fixtures into the database: python manage.py test api.tests
Yamuk
  • 750
  • 8
  • 27
Tho
  • 23,158
  • 6
  • 60
  • 47
3

I did this and I didn't have to give a path reference, the fixture file name was enough for me.

class SomeTest(TestCase):

    fixtures = ('myfixture.json',)
Andres
  • 4,323
  • 7
  • 39
  • 53
  • 1
    I'd like to also point out that the `.json` extension is optional too. –  Sep 21 '15 at 01:58
  • 2
    Note that if you aren't using great practices, and you paste the same fixture around with minor tweaks with the same name in different apps, django might load the wrong fixture if you don't list an explicit path to the correct fixture in your test file. Don't assume it will only look in your current app's fixture dir. – Nick Brady Jun 16 '16 at 19:23
2

You have two options, depending on whether you have a fixture, or you have a set of Python code to populate the data.

For fixtures, use cls.fixtures, like shown in an answer to this question,

class MyTestCase(django.test.TestCase):
    fixtures = ['/myapp/fixtures/dump.json',]

For Python, use cls.setUpTestData:

class MyTestCase(django.test.TestCase):
    @classmethod
    def setUpTestData(cls):
        cls.create_fixture()  # create_fixture is a custom function

setUpTestData is called by the TestCase.setUpClass.

You can use both, in which case fixtures is loaded first because setUpTestData is called after loading the fixtures.

Community
  • 1
  • 1
Jorge Leitao
  • 19,085
  • 19
  • 85
  • 121
  • What kind of code will `create_fuxture` have? I am trying to use fixtures. Even though I specify it correctly, my test is calling db. Why? What did I miss? Is it `create_fixture` logic? – Hussain Feb 07 '17 at 07:47
1

You need to import from django.test import TestCase and NOT from unittest import TestCase. That fixed the problem for me.

Ron
  • 22,128
  • 31
  • 108
  • 206
0

If you have overridden setUpClass method, make sure you call super().setUpClass() method as the first line in the method. The code to load fixtures is in TestCase class.

saurabheights
  • 3,967
  • 2
  • 31
  • 50