annotate nosedjango/nosedjango.py @ 5:22ae9aa457af

excercise more bits of the django 1.0b1 test framework
author Victor Ng <victor@monkeybean.ca>
date Thu, 28 Aug 2008 11:29:21 -0400
parents b761c26773a3
children dfba3a3a4343
rev   line source
0
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
1 """
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
2 nose plugin for easy testing of django projects and apps. Sets up a test
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
3 database (or schema) and installs apps from test settings file before tests
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
4 are run, and tears the test database (or schema) down after all tests are run.
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
5 """
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
6
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
7 import os, sys
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
8 import re
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
9
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
10 from nose.plugins import Plugin
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
11 import nose.case
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
12
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
13 # Force settings.py pointer
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
14 # search the current working directory and all parent directories to find
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
15 # the settings file
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
16 from nose.importer import add_path
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
17 os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
5
22ae9aa457af excercise more bits of the django 1.0b1 test framework
Victor Ng <victor@monkeybean.ca>
parents: 3
diff changeset
18 import re
22ae9aa457af excercise more bits of the django 1.0b1 test framework
Victor Ng <victor@monkeybean.ca>
parents: 3
diff changeset
19 NT_ROOT = re.compile(r"^[a-zA-Z]:\\$")
0
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
20 def get_SETTINGS_PATH():
5
22ae9aa457af excercise more bits of the django 1.0b1 test framework
Victor Ng <victor@monkeybean.ca>
parents: 3
diff changeset
21 '''
22ae9aa457af excercise more bits of the django 1.0b1 test framework
Victor Ng <victor@monkeybean.ca>
parents: 3
diff changeset
22 Hunt down the settings.py module by going up the FS path
22ae9aa457af excercise more bits of the django 1.0b1 test framework
Victor Ng <victor@monkeybean.ca>
parents: 3
diff changeset
23 '''
0
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
24 cwd = os.getcwd()
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
25 while cwd:
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
26 if 'settings.py' in os.listdir(cwd):
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
27 break
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
28 cwd = os.path.split(cwd)[0]
5
22ae9aa457af excercise more bits of the django 1.0b1 test framework
Victor Ng <victor@monkeybean.ca>
parents: 3
diff changeset
29 if os.name == 'nt' and NT_ROOT.match(cwd):
22ae9aa457af excercise more bits of the django 1.0b1 test framework
Victor Ng <victor@monkeybean.ca>
parents: 3
diff changeset
30 return None
22ae9aa457af excercise more bits of the django 1.0b1 test framework
Victor Ng <victor@monkeybean.ca>
parents: 3
diff changeset
31 elif cwd == '/':
0
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
32 return None
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
33 return cwd
5
22ae9aa457af excercise more bits of the django 1.0b1 test framework
Victor Ng <victor@monkeybean.ca>
parents: 3
diff changeset
34
0
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
35 SETTINGS_PATH = get_SETTINGS_PATH()
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
36
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
37
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
38 class NoseDjango(Plugin):
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
39 """
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
40 Enable to set up django test environment before running all tests, and
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
41 tear it down after all tests. If the django database engine in use is not
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
42 sqlite3, one or both of --django-test-db or django-test-schema must be
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
43 specified.
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
44
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
45 Note that your django project must be on PYTHONPATH for the settings file
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
46 to be loaded. The plugin will help out by placing the nose working dir
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
47 into sys.path if it isn't already there, unless the -P
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
48 (--no-path-adjustment) argument is set.
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
49 """
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
50 name = 'django'
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
51
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
52 def configure(self, options, conf):
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
53 Plugin.configure(self, options, conf)
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
54 self.verbosity = conf.verbosity
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
55
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
56 def begin(self):
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
57 """Create the test database and schema, if needed, and switch the
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
58 connection over to that database. Then call install() to install
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
59 all apps listed in the loaded settings module.
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
60 """
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
61 # Add the working directory (and any package parents) to sys.path
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
62 # before trying to import django modules; otherwise, they won't be
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
63 # able to find project.settings if the working dir is project/ or
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
64 # project/..
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
65
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
66 if not SETTINGS_PATH:
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
67 sys.stderr.write("Can't find Django settings file!\n")
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
68 # short circuit if no settings file can be found
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
69 return
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
70
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
71 if self.conf.addPaths:
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
72 map(add_path, self.conf.where)
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
73
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
74 add_path(SETTINGS_PATH)
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
75 sys.path.append(SETTINGS_PATH)
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
76 import settings
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
77 settings.DEBUG = False # I have no idea why Django does this, but it does
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
78 from django.core import mail
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
79 self.mail = mail
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
80 from django.conf import settings
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
81 from django.core import management
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
82 from django.test.utils import setup_test_environment
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
83 from django.db import connection
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
84
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
85 self.old_db = settings.DATABASE_NAME
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
86
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
87 # setup the test env for each test case
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
88 setup_test_environment()
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
89 connection.creation.create_test_db(verbosity=self.verbosity)
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
90
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
91 # exit the setup phase and let nose do it's thing
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
92
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
93 def beforeTest(self, test):
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
94
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
95 if not SETTINGS_PATH:
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
96 # short circuit if no settings file can be found
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
97 return
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
98
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
99 from django.core.management import call_command
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
100 call_command('flush', verbosity=0, interactive=False)
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
101
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
102 if isinstance(test, nose.case.Test) and \
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
103 isinstance(test.test, nose.case.MethodTestCase) and \
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
104 hasattr(test.context, 'fixtures'):
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
105 # We have to use this slightly awkward syntax due to the fact
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
106 # that we're using *args and **kwargs together.
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
107 call_command('loaddata', *test.context.fixtures, **{'verbosity': 0})
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
108 self.mail.outbox = []
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
109
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
110 def finalize(self, result=None):
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
111 """
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
112 Clean up any created database and schema.
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
113 """
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
114 if not SETTINGS_PATH:
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
115 # short circuit if no settings file can be found
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
116 return
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
117
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
118 from django.test.utils import teardown_test_environment
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
119 from django.db import connection
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
120 connection.creation.destroy_test_db(self.old_db, verbosity=self.verbosity)
ff263bdd455e initial checkin
Victor Ng <victor@monkeybean.ca>
parents:
diff changeset
121 teardown_test_environment()