Django ignoring fixtures when run from tests - django

I have a simple class in a Django app called "project"
from django.test import TestCase
class ProjectTest(TestCase):
"""Unit tests for the "Project" app """
fixtures = ['test_data.json', ]
def setUp(self):
pass
def testTotalAmountOfWhuffie(self):
"""Tests that the calculation to find the total amount of Whuffie allocated is correct."""
pass
if __name__ == '__main__':
unittest.main()
and when I run
manage.py test project
it completely ignores the fixtures. If I rename the file to initial_data.json it gets picked up by the test runner, so I'm sure the directory structure is right.
If I increase the verbosity of the test runs, they don't even look for the fixtures that I specify, I can even go as far as specifying the full path to the file, and they don't get loaded.

If 'test_data.json' is under project/fixtures, then I can't see any problem with what you have got. Try using the fixture data in a test.
"it completely ignores the fixtures"
How do you know this?
"If I rename the file to initial_data.json it gets picked up by the test runner"
This is only picked up because the test runner runs syncdb. See http://docs.djangoproject.com/en/dev/howto/initial-data/#automatically-loading-initial-data-fixtures
"If I increase the verbosity of the test runs, they don't even look for the fixtures that I specify,"
How can you be sure? I ran my tests with the verbosity set to 3, and the test runner did not mention my fixtures at all. (The tests work)
I even tried using a non-existent fixture in the test. Again, the test runner did not mention any problem.

Related

How to load fixtures for a LiveServerTestCase

I am attempting to write test cases in Django using Selenium. I want to use existent fixtures so my test database (SQLite3) has test data for every test.
I have some model test cases (just using the TestCase class) as follows;
from django.test import TestCase
from django.test import LiveServerTestCases
from missions.models import Mission, MissionDataRecord
class MissionModelTests(TestCase):
fixtures = ['myproject_common/fixtures/auth_initial_load.json', 'worklog/fixtures/worklogs_initial_load',
'missions_initial_load.json']
def test_object_name_is_mission_title(self):
mission = Mission.objects.get(id=1)
self.assertEqual(mission.title, str(mission))
def test_object_name_is_mission_title_again(self):
mission = Mission.objects.get(id=1)
self.assertEqual(mission.title, str(mission))
This works as expected when run like this (I get two test passes). However, for Selenium testing I need to use LiveServerTestCase instead of TestCase.
The simple example above is a model test, but for illustrative purposes of the issue I'm facing with Selenium, if I simply replace "TestCase" with "LiveServerTestCase" the first test passes, but the second test fails, with the error
django.db.utils.IntegrityError: Problem installing fixture
'[...]/fixtures/auth_initial_load.json': Could not load
auth.User(pk=1): UNIQUE constraint failed: auth_user.username
This error occurs in the _fixture_setup of /django/test/testcases.py. This seems to suggests that my fixtures (specifically the auth_initial_load fixture) is attempting to load again ON TOP of existing data. However, from django docs reading this should not be taking place, because each test should run in its own transaction (which I believe means the fixtures are loaded for each transaction).
What is going on here, and more importantly, how can I use LiveServerTestCase with my existing fixtures (similar to how I am using TestCase currently)? In reality I need to use StaticLiveServerTestCase, but Im guessing the code will be the same.
It turns out the way I was loading fixtures correctly after all. The issue was with my fixtures themselves, using hard coded primary (and foreign) keys. In my case two users were being created before the fixtures were loaded, so when fixtures tried to load with the same primary key, a UNIQUE constraint violation occurred. The solution was to re-generate my fixtures using the --natural-primary and --natural-foreign flags as suggested in this SO answer.

Overriding TEST_RUNNER with #override_settings

In order to run my tests faster I created a no db test runner as in this answer. Then I needed to set the TEST_RUNNER settings variable to my new test runner but only for certain tests. To achieve this, I tried using django.test.utils.override_settings decorator like this (as in the docs):
from django.test import TestCase
from django.test.utils import override_settings
class MyTestCase(TestCase):
#override_settings(TEST_RUNNER='path_to_my_no_db_test_runner')
def test_my_test_case(self):
...
The problem is that when I run this test, django will still create the database, which is not the expected behavior of course. The curious thing is that if I set the TEST_RUNNER directly in my settings.py it works perfectly, but with django.test.utils.override_settings it seems to have no effect. I also tried using this override_settings module but got the same results.
What am I dping wrong? Is there any other way of achieving this? I'd rather not to create a test_settings.py and run my tests with --settings argument.
Put this piece of code in your config :
TESTING = 'test' in sys.argv
...
if TESTING:
TEST_RUNNER = 'path_to_my_no_db_test_runner'
DATABASES = {}
The TESTING setting will be defined only when you run tests, you can then dynamically change some settings including your DB, migrations, test runners...
It will be loaded at the very beginning of Django initialisation therefore if you override DATABASES no DBs will be created.

Keep table data during Django tests

I have some tables containing a lot of data (imported from geonames using django-cities: https://github.com/coderholic/django-cities) that I want to preserve in tests (since loading them via fixtures will be very slow)… how can I keep those tables and their data during tests?
I think I have to write a custom TestRunner, but I have no idea about where to start :P
It's possible, here is a way :
1) Define your own test runner look here to see how.
2) For your custom test runner look in the default test runner, you can just copy and past the code and just comment this line : connection.creation.destroy_test_db(old_name, verbosity) which is responsible for destroying the test database, and i think you should put the connection.creation.create_test_db(..) line in a try except something like this maybe:
try:
# Create the database the first time.
connection.creation.create_test_db(verbosity, autoclobber=not interactive)
except ..: # Look at the error that this will raise when create a database that already exist
# Test database already created.
pass
3) Bound TEST_RUNNER in setting.py to your test runner.
4) Now run your test like this: ./manage.py test

run every TestCase inside a module

How can you run tests from all TestCase classes, in a specific module under tests package?
In a Django project, I have split tests.py under tests/
Each file(module) has several TestCase classes, and each of them having several test methods.
init.py imports each of them.
I already know that I can do these:
Run all the test:
./manage.py test myapp
Or run specific TestCase:
./manage.py test myapp.OneOfManyTestCase
Or run very specific test method from a TestCase class:
./manage.py test myapp.OneOfManyTestCase.test_some_small_method
However, I can't figure out how to run every TestCases from a particular module.
Say, OneOfManyTestCase class is from tests/lot_of_test.py, and there are other test cases too.
Django doesn't seem to care about modules with TestCases.
How can I run all the TestCases inside lot_of_test?
I think to achieve this you need to subclass your own TestRunner from DjangoTestSuiteRunner and override build_suite method.
I ended up writing down my own TestSuiteRunner, like #sneawo said.
After Django-style fails, try importing as usual python-style.
One line to fix:
suite.addTest(build_test(label))
into
try:
suite.addTest(django.test.simple.build_test(label))
except ValueError:
# change to python-style package name
head, tail = label.split('.', 1)
full_label = '.'.join([head, django.test.simple.TEST_MODULE, tail])
# load tests
tests = unittest.defaultTestLoader.loadTestsFromName(full_label)
suite.addTests(tests)
and set TEST_RUNNER in settings.py:
TEST_RUNNER='myapp.tests.module_test_suite_runner.ModuleTestSuiteRunner'

Django Unit Test fails project-wide but passes app-wide

I'm using Django 1.4 with Python 2.7 on Ubuntu 12.10.
I have a project with several apps and dozens of unit tests. We've recently run into a little issue using the #override_settings decorator.
Here is some code:
#override_settings(MEDIA_URL='/test/media/')
def test_get_content_dict(self):
self.assertEqual(
self.offer.get_content_dict(),
{ 'some stuff': some stuff }
When tests are run at the app level everything passes.
python manage.py test my_app --settings=proton.settings.test
But when we run at the project level it fails.
python manage.py test --settings=proton.settings.test
It's failing due to some stuff using /test/media but the model method offer.get_contect_dict() using /media, which is our actual MEDIA_URL.
We can change the MEDIA_URL in our settings/test.py file, but that would require all tests to use /test/media (which might be a good idea anyway).
Clearly the problem is in Django's core.files.storage.FileSystemStorage.__init__() - it sets the base_url earlier in the test suite but does not re-instantiate the object after each test (for obvious reasons) so the #override_settings doesn't actually do anything.
Is this a bug or is this working as intended? Any suggestions to an elegant solution other than forcing all unit tests to use /test/media by setting our MEDIA_URL constant in our settings/test.py to /test/media?