diff 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
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/nosedjango/nosedjango.py	Thu Aug 28 09:44:43 2008 -0400
@@ -0,0 +1,118 @@
+"""
+nose plugin for easy testing of django projects and apps. Sets up a test
+database (or schema) and installs apps from test settings file before tests
+are run, and tears the test database (or schema) down after all tests are run.
+"""
+__author = 'Jason Pellerin'
+__version__ = '0.1'
+
+import atexit
+import logging
+import os, sys
+import re
+
+from nose.plugins import Plugin
+import nose.case
+
+# Force settings.py pointer
+# search the current working directory and all parent directories to find
+# the settings file
+from nose.importer import add_path
+os.environ['DJANGO_SETTINGS_MODULE'] = 'settings'
+def get_SETTINGS_PATH():
+    cwd = os.getcwd()
+    while cwd:
+        if 'settings.py' in os.listdir(cwd):
+            break
+        cwd = os.path.split(cwd)[0]
+        if cwd == '/':
+            return None
+    return cwd
+SETTINGS_PATH = get_SETTINGS_PATH()
+
+log = logging.getLogger('nose.plugins.nosedjango')
+
+class NoseDjango(Plugin):
+    """
+    Enable to set up django test environment before running all tests, and
+    tear it down after all tests. If the django database engine in use is not
+    sqlite3, one or both of --django-test-db or django-test-schema must be
+    specified.
+
+    Note that your django project must be on PYTHONPATH for the settings file
+    to be loaded. The plugin will help out by placing the nose working dir
+    into sys.path if it isn't already there, unless the -P
+    (--no-path-adjustment) argument is set.
+    """
+    name = 'django'
+
+    def configure(self, options, conf):
+        Plugin.configure(self, options, conf)
+        self.verbosity = conf.verbosity
+
+    def begin(self):
+        """Create the test database and schema, if needed, and switch the
+        connection over to that database. Then call install() to install
+        all apps listed in the loaded settings module.
+        """
+        # Add the working directory (and any package parents) to sys.path
+        # before trying to import django modules; otherwise, they won't be
+        # able to find project.settings if the working dir is project/ or
+        # project/..
+
+        if not SETTINGS_PATH:
+            sys.stderr.write("Can't find Django settings file!\n")
+            # short circuit if no settings file can be found
+            return
+
+        if self.conf.addPaths:
+            map(add_path, self.conf.where)
+
+        add_path(SETTINGS_PATH)
+        sys.path.append(SETTINGS_PATH)
+        import settings
+        settings.DEBUG = False # I have no idea why Django does this, but it does
+        from django.core import mail
+        self.mail = mail
+        from django.conf import settings
+        from django.core import management
+        from django.test.utils import setup_test_environment
+        from django.db import connection
+
+        self.old_db = settings.DATABASE_NAME
+
+        # setup the test env for each test case
+        setup_test_environment()
+        connection.creation.create_test_db(verbosity=self.verbosity)
+
+        # exit the setup phase and let nose do it's thing
+            
+    def beforeTest(self, test):
+
+        if not SETTINGS_PATH:
+            # short circuit if no settings file can be found
+            return
+
+        from django.core.management import call_command
+        call_command('flush', verbosity=0, interactive=False)
+
+        if isinstance(test, nose.case.Test) and \
+            isinstance(test.test, nose.case.MethodTestCase) and \
+            hasattr(test.context, 'fixtures'):
+                # We have to use this slightly awkward syntax due to the fact
+                # that we're using *args and **kwargs together.
+                call_command('loaddata', *test.context.fixtures, **{'verbosity': 0}) 
+        self.mail.outbox = []
+
+    def finalize(self, result=None):
+        """
+        Clean up any created database and schema.
+        """
+        if not SETTINGS_PATH:
+            # short circuit if no settings file can be found
+            return
+
+        from django.test.utils import teardown_test_environment
+        from django.db import connection
+        connection.creation.destroy_test_db(self.old_db, verbosity=self.verbosity)   
+        teardown_test_environment()