So I’ve been trying to write unit tests for Django, but, as I’m doing a lot of work on a shared hoster, this isn’t working. The problem is that our user account doesn’t have CREATE/DROP DATABASE privileges on the server. This has been documented here, here, here, and here.
Which means I see the following if I try to run manage.py test
, I get:
1
2
3
4
5
|
Creating test database for alias 'default'...
Got an error creating the test database: permission denied to create database
Type 'yes' if you would like to try deleting the test database 'database_dev', or 'no' to cancel: no
Tests cancelled.
|
Unfortunately, there isn’t a first-class solution from the Django devs, so after reading that django-nose had a handy REUSE_DB parameter, I tried to install django-nose.
1 |
pip install --no-deps django-nose
|
(no-deps because I’m working with Django 1.5 beta 1)
Then, in settings.py, I set TEST_RUNNER=’django_nose.NoseTestSuiteRunner’, and set the TEST_NAME key on your ‘default’ DATABASES entry to the same value as NAME.
Unfortunately, you still get errors, if you’re trying to use PostGIS, seems like transactions may not be a happy thing there:
1
2
3
4
5
6
|
$ REUSE_DB=1 python2.7 manage.py test
/home/user/lib/python2.7/nose/util.py:14: DeprecationWarning: The compiler package is deprecated and removed in Python 3.x.
from compiler.consts import CO_GENERATOR
nosetests --verbosity 1
AttributeError: 'PostGISCreation' object has no attribute '_rollback_works'
|
So it looks like the only option I now have is to write unit tests that just run against a development database, and do a decent job of cleaning up after themselves in the setUp and tearDown methods. Using the standard nose distribution will do this, but if you just do “pip install nose” and try using “nosetests”, it will error out:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
======================================================================
ERROR: Failure: ImportError (No module named django.test)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/user/lib/python2.7/nose/loader.py", line 390, in loadTestsFromName
addr.filename, addr.module)
File "/home/user/lib/python2.7/nose/importer.py", line 39, in importFromPath
return self.importFromDir(dir_path, fqname)
File "/home/user/lib/python2.7/nose/importer.py", line 86, in importFromDir
mod = load_module(part_fqname, fh, filename, desc)
File "/app/polls/tests.py", line 8, in <module>
from django.test import TestCase
ImportError: No module named django.test
|
The problem is that nose doesn’t know about Django’s settings or modules. You have to make a copy of nosetests into the same directory where “manage.py” is located and change it so the DJANGO_SETTINGS_MODULE is incorporated into the os.environ resource. Like so:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
$ cat nosetests
#!/usr/local/bin/python2.7
# EASY-INSTALL-ENTRY-SCRIPT: 'nose==1.2.1','console_scripts','nosetests'
__requires__ = 'nose==1.2.1'
import os
import sys
from pkg_resources import load_entry_point
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "settings")
sys.exit(
load_entry_point('nose==1.2.1', 'console_scripts', 'nosetests')()
)
|
Then you’ll see:
$ ./nosetests
……
———————————————————————-
Ran 6 tests in 4.955s
OK
$