Django tests complain of missing tables
Since you're using a legacy database, you are probably not adding the app name to INSTALLED_APPS. If an app is not included in INSTALLED_APPS, the tables for the apps' models will not get created on syncdb. This works for you in production since you already have a table, but not in test environment.
You can adopt any of the following:
The supermonkeypatch way: Take out app_name from Customer class Meta, put the model in a models.py file inside a python module name mcif, and add mcif to INSTALLED_APPS - just for the sake of testing
The nicer way: Extend DjangoTestSuiteRunner and override setup_test_environment to call super and then create your legacy table manually in the test DB.
The nicest way: Put your model in properly named app module. Remove app_name from model Meta but add managed=False docs. Include app name in INSTALLED_APPS. Now django will not create table for that model. Then use this nice snippet the Caktus group folks have compiled to run your tests.
Cheers!
Edit - How to use the overridden DjangoTestSuiteRunner
You will need at least Django 1.2 for this.
Copy the code from here. Put it in utils.py inside the mcif app.
Add/edit the following in settings.py:
TEST_RUNNER = 'mcif.utils.ManagedModelTestRunner'
Now when you run tests, all unmanaged tables will be treated as managed table only for the duration of the test. So the tables will be created prior to running tests.
Notice this part of the code, thats where the magic happens.
self.unmanaged_models = [m for m in get_models() if not m._meta.managed]
for m in self.unmanaged_models:
m._meta.managed = True
2nd Edit: Possible Gotchas
Make sure of the following:
- The DB user has privilege to create databases and not only tables because django will try to create a test database
- The test cases extend django.test.TransactionTestCase, since you have transactional behavior
- If none of the above applies, put a pdb in ManagedModelTestRunner's setup_test_environment just to make sure the code is being reached. Because if that code is reached, the table should get created
3rd Edit: Debugging Inside mcif.utils.ManagedModelTestRunner replace setup_test_environment function with the following and let me know if the output of your test changes:
def setup_test_environment(self, *args, **kwargs):
print "Loading ManagedModelTestRunner"
from django.db.models.loading import get_models
self.unmanaged_models = [m for m in get_models()
if not m._meta.managed]
for m in self.unmanaged_models:
print "Modifying model %s to be managed for testing" % m
m._meta.managed = True
super(ManagedModelTestRunner, self).setup_test_environment(*args, **kwargs)
The solutions presented by tarequeh worked for me after overriding DATABASE_ROUTERS.
I am using routers in order to prevent writes on the legacy database. In order to get around this I created a test_settings file with the following contents:
from settings import *
DEBUG = True
TEST_RUNNER = 'legacy.utils.ManagedModelTestRunner'
DATABASE_ROUTERS = []
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.sqlite3',
'NAME': os.path.join(HERE, 'test.db'),
},
}
Then when running tests:
python manage.py test [app_name] --settings=test_settings