annotate nosedjango/nosedjango.py @ 0:ff263bdd455e

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