django-nose-1.2/0000755000076500000240000000000012173536173014321 5ustar jbaloghstaff00000000000000django-nose-1.2/changelog.txt0000644000076500000240000000123512124726631017006 0ustar jbaloghstaff00000000000000(Later entries are in the readme.) - 0.1.2 (08-14-10) * run_tests API support (carjm) * better coverage numbers (rozza & miracle2k) * support for adding custom nose plugins (kumar303) - 0.1.1 (06-01-10) * Cleaner installation (Michael Fladischer) - 0.1 (05-18-10) * Class-based test runner (Antti Kaihola) * Django 1.2 compatibility (Antti Kaihola) * Mapping Django verbosity to nose verbosity - 0.0.3 (12-31-09) * Python 2.4 support (Blake Winton) * GeoDjango spatial database support (Peter Baumgartner) * Return the number of failing tests on the command line - 0.0.2 (10-01-09) * rst readme (Rob Madole) - 0.0.1 (10-01-09) * birth! django-nose-1.2/django_nose/0000755000076500000240000000000012173536173016607 5ustar jbaloghstaff00000000000000django-nose-1.2/django_nose/__init__.py0000644000076500000240000000032412124726631020713 0ustar jbaloghstaff00000000000000VERSION = (1, 1, 0) __version__ = '.'.join(map(str, VERSION)) from django_nose.runner import * from django_nose.testcases import * # Django < 1.2 compatibility. run_tests = run_gis_tests = NoseTestSuiteRunner django-nose-1.2/django_nose/fixture_tables.py0000644000076500000240000001435112164614730022201 0ustar jbaloghstaff00000000000000"""A copy of Django 1.3.0's stock loaddata.py, adapted so that, instead of loading any data, it returns the tables referenced by a set of fixtures so we can truncate them (and no others) quickly after we're finished with them.""" import os import gzip import zipfile from itertools import product from django.conf import settings from django.core import serializers from django.db import router, DEFAULT_DB_ALIAS from django.db.models import get_apps try: import bz2 has_bz2 = True except ImportError: has_bz2 = False def tables_used_by_fixtures(fixture_labels, using=DEFAULT_DB_ALIAS): """Act like Django's stock loaddata command, but, instead of loading data, return an iterable of the names of the tables into which data would be loaded.""" # Keep a count of the installed objects and fixtures fixture_count = 0 loaded_object_count = 0 fixture_object_count = 0 tables = set() class SingleZipReader(zipfile.ZipFile): def __init__(self, *args, **kwargs): zipfile.ZipFile.__init__(self, *args, **kwargs) if settings.DEBUG: assert len(self.namelist()) == 1, "Zip-compressed fixtures must contain only one file." def read(self): return zipfile.ZipFile.read(self, self.namelist()[0]) compression_types = { None: file, 'gz': gzip.GzipFile, 'zip': SingleZipReader } if has_bz2: compression_types['bz2'] = bz2.BZ2File app_module_paths = [] for app in get_apps(): if hasattr(app, '__path__'): # It's a 'models/' subpackage for path in app.__path__: app_module_paths.append(path) else: # It's a models.py module app_module_paths.append(app.__file__) app_fixtures = [os.path.join(os.path.dirname(path), 'fixtures') for path in app_module_paths] for fixture_label in fixture_labels: parts = fixture_label.split('.') if len(parts) > 1 and parts[-1] in compression_types: compression_formats = [parts[-1]] parts = parts[:-1] else: compression_formats = list(compression_types.keys()) if len(parts) == 1: fixture_name = parts[0] formats = serializers.get_public_serializer_formats() else: fixture_name, format = '.'.join(parts[:-1]), parts[-1] if format in serializers.get_public_serializer_formats(): formats = [format] else: formats = [] if not formats: # stderr.write(style.ERROR("Problem installing fixture '%s': %s is # not a known serialization format.\n" % (fixture_name, format))) return set() if os.path.isabs(fixture_name): fixture_dirs = [fixture_name] else: fixture_dirs = app_fixtures + list(settings.FIXTURE_DIRS) + [''] for fixture_dir in fixture_dirs: # stdout.write("Checking %s for fixtures...\n" % # humanize(fixture_dir)) label_found = False for combo in product([using, None], formats, compression_formats): database, format, compression_format = combo file_name = '.'.join( p for p in [ fixture_name, database, format, compression_format ] if p ) # stdout.write("Trying %s for %s fixture '%s'...\n" % \ # (humanize(fixture_dir), file_name, fixture_name)) full_path = os.path.join(fixture_dir, file_name) open_method = compression_types[compression_format] try: fixture = open_method(full_path, 'r') if label_found: fixture.close() # stderr.write(style.ERROR("Multiple fixtures named # '%s' in %s. Aborting.\n" % (fixture_name, # humanize(fixture_dir)))) return set() else: fixture_count += 1 objects_in_fixture = 0 loaded_objects_in_fixture = 0 # stdout.write("Installing %s fixture '%s' from %s.\n" # % (format, fixture_name, humanize(fixture_dir))) try: objects = serializers.deserialize(format, fixture, using=using) for obj in objects: objects_in_fixture += 1 if router.allow_syncdb(using, obj.object.__class__): loaded_objects_in_fixture += 1 tables.add( obj.object.__class__._meta.db_table) loaded_object_count += loaded_objects_in_fixture fixture_object_count += objects_in_fixture label_found = True except (SystemExit, KeyboardInterrupt): raise except Exception: fixture.close() # stderr.write( style.ERROR("Problem installing # fixture '%s': %s\n" % (full_path, ''.join(tra # ceback.format_exception(sys.exc_type, # sys.exc_value, sys.exc_traceback))))) return set() fixture.close() # If the fixture we loaded contains 0 objects, assume that an # error was encountered during fixture loading. if objects_in_fixture == 0: # stderr.write( style.ERROR("No fixture data found # for '%s'. (File format may be invalid.)\n" % # (fixture_name))) return set() except Exception: # stdout.write("No %s fixture '%s' in %s.\n" % \ (format, # fixture_name, humanize(fixture_dir))) pass return tables django-nose-1.2/django_nose/management/0000755000076500000240000000000012173536173020723 5ustar jbaloghstaff00000000000000django-nose-1.2/django_nose/management/__init__.py0000644000076500000240000000000012124726631023016 0ustar jbaloghstaff00000000000000django-nose-1.2/django_nose/management/commands/0000755000076500000240000000000012173536173022524 5ustar jbaloghstaff00000000000000django-nose-1.2/django_nose/management/commands/__init__.py0000644000076500000240000000000012124726631024617 0ustar jbaloghstaff00000000000000django-nose-1.2/django_nose/management/commands/test.py0000644000076500000240000000157612124726631024062 0ustar jbaloghstaff00000000000000""" Add extra options from the test runner to the ``test`` command, so that you can browse all the nose options from the command line. """ from django.conf import settings from django.test.utils import get_runner if 'south' in settings.INSTALLED_APPS: from south.management.commands.test import Command else: from django.core.management.commands.test import Command # Django < 1.2 compatibility test_runner = settings.TEST_RUNNER if test_runner.endswith('run_tests') or test_runner.endswith('run_gis_tests'): import warnings warnings.warn( 'Use `django_nose.NoseTestSuiteRunner` instead of `%s`' % test_runner, DeprecationWarning) TestRunner = get_runner(settings) if hasattr(TestRunner, 'options'): extra_options = TestRunner.options else: extra_options = [] class Command(Command): option_list = Command.option_list + tuple(extra_options) django-nose-1.2/django_nose/plugin.py0000644000076500000240000002352312160626121020451 0ustar jbaloghstaff00000000000000import sys from nose.plugins.base import Plugin from nose.suite import ContextSuite from django.test.testcases import TransactionTestCase, TestCase from django_nose.testcases import FastFixtureTestCase from django_nose.utils import process_tests, is_subclass_at_all class AlwaysOnPlugin(Plugin): """A plugin that takes no options and is always enabled""" def options(self, parser, env): """Avoid adding a ``--with`` option for this plugin. We don't have any options, and this plugin is always enabled, so we don't want to use superclass's ``options()`` method which would add a ``--with-*`` option. """ def configure(self, *args, **kw_args): super(AlwaysOnPlugin, self).configure(*args, **kw_args) self.enabled = True # Force this plugin to be always enabled. class ResultPlugin(AlwaysOnPlugin): """Captures the TestResult object for later inspection nose doesn't return the full test result object from any of its runner methods. Pass an instance of this plugin to the TestProgram and use ``result`` after running the tests to get the TestResult object. """ name = 'result' def finalize(self, result): self.result = result class DjangoSetUpPlugin(AlwaysOnPlugin): """Configures Django to set up and tear down the environment This allows coverage to report on all code imported and used during the initialization of the test runner. """ name = 'django setup' def __init__(self, runner): super(DjangoSetUpPlugin, self).__init__() self.runner = runner self.sys_stdout = sys.stdout def prepareTest(self, test): """Create the Django DB and model tables, and do other setup. This isn't done in begin() because that's too early--the DB has to be set up *after* the tests are imported so the model registry contains models defined in tests.py modules. Models are registered at declaration time by their metaclass. prepareTestRunner() might also have been a sane choice, except that, if some plugin returns something from it, none of the other ones get called. I'd rather not dink with scores if I don't have to. """ # What is this stdout switcheroo for? sys_stdout = sys.stdout sys.stdout = self.sys_stdout self.runner.setup_test_environment() self.old_names = self.runner.setup_databases() sys.stdout = sys_stdout def finalize(self, result): self.runner.teardown_databases(self.old_names) self.runner.teardown_test_environment() class Bucketer(object): def __init__(self): # { (frozenset(['users.json']), True): # [ContextSuite(...), ContextSuite(...)] } self.buckets = {} # All the non-FastFixtureTestCase tests we saw, in the order they came # in: self.remainder = [] def add(self, test): """Put a test into a bucket according to its set of fixtures and the value of its exempt_from_fixture_bundling attr.""" if is_subclass_at_all(test.context, FastFixtureTestCase): # We bucket even FFTCs that don't have any fixtures, but it # shouldn't matter. key = (frozenset(getattr(test.context, 'fixtures', [])), getattr(test.context, 'exempt_from_fixture_bundling', False)) self.buckets.setdefault(key, []).append(test) else: self.remainder.append(test) class TestReorderer(AlwaysOnPlugin): """Reorder tests for various reasons.""" name = 'django-nose-test-reorderer' def options(self, parser, env): super(TestReorderer, self).options(parser, env) # pointless parser.add_option('--with-fixture-bundling', action='store_true', dest='with_fixture_bundling', default=env.get('NOSE_WITH_FIXTURE_BUNDLING', False), help='Load a unique set of fixtures only once, even ' 'across test classes. ' '[NOSE_WITH_FIXTURE_BUNDLING]') def configure(self, options, conf): super(TestReorderer, self).configure(options, conf) self.should_bundle = options.with_fixture_bundling def _put_transaction_test_cases_last(self, test): """Reorder tests in the suite so TransactionTestCase-based tests come last. Django has a weird design decision wherein TransactionTestCase doesn't clean up after itself. Instead, it resets the DB to a clean state only at the *beginning* of each test: https://docs.djangoproject.com/en/dev/topics/testing/?from=olddocs# django. test.TransactionTestCase. Thus, Django reorders tests so TransactionTestCases all come last. Here we do the same. "I think it's historical. We used to have doctests also, adding cleanup after each unit test wouldn't necessarily clean up after doctests, so you'd have to clean on entry to a test anyway." was once uttered on #django-dev. """ def filthiness(test): """Return a comparand based on whether a test is guessed to clean up after itself. Django's TransactionTestCase doesn't clean up the DB on teardown, but it's hard to guess whether subclasses (other than TestCase) do. We will assume they don't, unless they have a ``cleans_up_after_itself`` attr set to True. This is reasonable because the odd behavior of TransactionTestCase is documented, so subclasses should by default be assumed to preserve it. Thus, things will get these comparands (and run in this order): * 1: TestCase subclasses. These clean up after themselves. * 1: TransactionTestCase subclasses with cleans_up_after_itself=True. These include FastFixtureTestCases. If you're using the FixtureBundlingPlugin, it will pull the FFTCs out, reorder them, and run them first of all. * 2: TransactionTestCase subclasses. These leave a mess. * 2: Anything else (including doctests, I hope). These don't care about the mess you left, because they don't hit the DB or, if they do, are responsible for ensuring that it's clean (as per https://docs.djangoproject.com/en/dev/topics/testing/?from= olddocs#writing-doctests) """ test_class = test.context if (is_subclass_at_all(test_class, TestCase) or (is_subclass_at_all(test_class, TransactionTestCase) and getattr(test_class, 'cleans_up_after_itself', False))): return 1 return 2 flattened = [] process_tests(test, flattened.append) flattened.sort(key=filthiness) return ContextSuite(flattened) def _bundle_fixtures(self, test): """Reorder the tests in the suite so classes using identical sets of fixtures are contiguous. I reorder FastFixtureTestCases so ones using identical sets of fixtures run adjacently. I then put attributes on them to advise them to not reload the fixtures for each class. This takes support.mozilla.com's suite from 123s down to 94s. FastFixtureTestCases are the only ones we care about, because nobody else, in practice, pays attention to the ``_fb`` advisory bits. We return those first, then any remaining tests in the order they were received. """ def suite_sorted_by_fixtures(suite): """Flatten and sort a tree of Suites by the ``fixtures`` members of their contexts. Add ``_fb_should_setup_fixtures`` and ``_fb_should_teardown_fixtures`` attrs to each test class to advise it whether to set up or tear down (respectively) the fixtures. Return a Suite. """ bucketer = Bucketer() process_tests(suite, bucketer.add) # Lay the bundles of common-fixture-having test classes end to end # in a single list so we can make a test suite out of them: flattened = [] for ((fixtures, is_exempt), fixture_bundle) in bucketer.buckets.items(): # Advise first and last test classes in each bundle to set up # and tear down fixtures and the rest not to: if fixtures and not is_exempt: # Ones with fixtures are sure to be classes, which means # they're sure to be ContextSuites with contexts. # First class with this set of fixtures sets up: first = fixture_bundle[0].context first._fb_should_setup_fixtures = True # Set all classes' 1..n should_setup to False: for cls in fixture_bundle[1:]: cls.context._fb_should_setup_fixtures = False # Last class tears down: last = fixture_bundle[-1].context last._fb_should_teardown_fixtures = True # Set all classes' 0..(n-1) should_teardown to False: for cls in fixture_bundle[:-1]: cls.context._fb_should_teardown_fixtures = False flattened.extend(fixture_bundle) flattened.extend(bucketer.remainder) return ContextSuite(flattened) return suite_sorted_by_fixtures(test) def prepareTest(self, test): """Reorder the tests.""" test = self._put_transaction_test_cases_last(test) if self.should_bundle: test = self._bundle_fixtures(test) return test django-nose-1.2/django_nose/runner.py0000644000076500000240000003571312173535770020505 0ustar jbaloghstaff00000000000000"""Django test runner that invokes nose. You can use... :: NOSE_ARGS = ['list', 'of', 'args'] in settings.py for arguments that you want always passed to nose. """ from __future__ import print_function import os import sys from optparse import make_option from types import MethodType from django.conf import settings from django.core import exceptions from django.core.management.base import BaseCommand from django.core.management.color import no_style from django.core.management.commands.loaddata import Command from django.db import connections, transaction, DEFAULT_DB_ALIAS, models from django.db.backends.creation import BaseDatabaseCreation from django.test.simple import DjangoTestSuiteRunner from django.utils.importlib import import_module import nose.core from django_nose.plugin import DjangoSetUpPlugin, ResultPlugin, TestReorderer from django_nose.utils import uses_mysql try: any except NameError: def any(iterable): for element in iterable: if element: return True return False __all__ = ['BasicNoseRunner', 'NoseTestSuiteRunner'] # This is a table of Django's "manage.py test" options which # correspond to nosetests options with a different name: OPTION_TRANSLATION = {'--failfast': '-x', '--nose-verbosity': '--verbosity'} def translate_option(opt): if '=' in opt: long_opt, value = opt.split('=', 1) return '%s=%s' % (translate_option(long_opt), value) return OPTION_TRANSLATION.get(opt, opt) # Django v1.2 does not have a _get_test_db_name() function. if not hasattr(BaseDatabaseCreation, '_get_test_db_name'): def _get_test_db_name(self): TEST_DATABASE_PREFIX = 'test_' if self.connection.settings_dict['TEST_NAME']: return self.connection.settings_dict['TEST_NAME'] return TEST_DATABASE_PREFIX + self.connection.settings_dict['NAME'] BaseDatabaseCreation._get_test_db_name = _get_test_db_name def _get_plugins_from_settings(): plugins = (list(getattr(settings, 'NOSE_PLUGINS', [])) + ['django_nose.plugin.TestReorderer']) for plug_path in plugins: try: dot = plug_path.rindex('.') except ValueError: raise exceptions.ImproperlyConfigured( "%s isn't a Nose plugin module" % plug_path) p_mod, p_classname = plug_path[:dot], plug_path[dot + 1:] try: mod = import_module(p_mod) except ImportError as e: raise exceptions.ImproperlyConfigured( 'Error importing Nose plugin module %s: "%s"' % (p_mod, e)) try: p_class = getattr(mod, p_classname) except AttributeError: raise exceptions.ImproperlyConfigured( 'Nose plugin module "%s" does not define a "%s"' % (p_mod, p_classname)) yield p_class() def _get_options(): """Return all nose options that don't conflict with django options.""" cfg_files = nose.core.all_config_files() manager = nose.core.DefaultPluginManager() config = nose.core.Config(env=os.environ, files=cfg_files, plugins=manager) config.plugins.addPlugins(list(_get_plugins_from_settings())) options = config.getParser()._get_all_options() # copy nose's --verbosity option and rename to --nose-verbosity verbosity = [o for o in options if o.get_opt_string() == '--verbosity'][0] verbosity_attrs = dict((attr, getattr(verbosity, attr)) for attr in verbosity.ATTRS if attr not in ('dest', 'metavar')) options.append(make_option('--nose-verbosity', dest='nose_verbosity', metavar='NOSE_VERBOSITY', **verbosity_attrs)) # Django 1.6 introduces a "--pattern" option, which is shortened into "-p" # do not allow "-p" to collide with nose's "--plugins" option. plugins_option = [o for o in options if o.get_opt_string() == '--plugins'][0] plugins_option._short_opts.remove('-p') django_opts = [opt.dest for opt in BaseCommand.option_list] + ['version'] return tuple(o for o in options if o.dest not in django_opts and o.action != 'help') class BasicNoseRunner(DjangoTestSuiteRunner): """Facade that implements a nose runner in the guise of a Django runner You shouldn't have to use this directly unless the additions made by ``NoseTestSuiteRunner`` really bother you. They shouldn't, because they're all off by default. """ __test__ = False # Replace the builtin command options with the merged django/nose options: options = _get_options() def run_suite(self, nose_argv): result_plugin = ResultPlugin() plugins_to_add = [DjangoSetUpPlugin(self), result_plugin, TestReorderer()] for plugin in _get_plugins_from_settings(): plugins_to_add.append(plugin) nose.core.TestProgram(argv=nose_argv, exit=False, addplugins=plugins_to_add) return result_plugin.result def run_tests(self, test_labels, extra_tests=None): """Run the unit tests for all the test names in the provided list. Test names specified may be file or module names, and may optionally indicate the test case to run by separating the module or file name from the test case name with a colon. Filenames may be relative or absolute. N.B.: The test_labels argument *MUST* be a sequence of strings, *NOT* just a string object. (Or you will be specifying tests for for each character in your string, and not the whole string. Examples: runner.run_tests( ('test.module',) ) runner.run_tests(['another.test:TestCase.test_method']) runner.run_tests(['a.test:TestCase']) runner.run_tests(['/path/to/test/file.py:test_function']) runner.run_tests( ('test.module', 'a.test:TestCase') ) Note: the extra_tests argument is currently ignored. You can run old non-nose code that uses it without totally breaking, but the extra tests will not be run. Maybe later. Returns the number of tests that failed. """ nose_argv = (['nosetests'] + list(test_labels)) if hasattr(settings, 'NOSE_ARGS'): nose_argv.extend(settings.NOSE_ARGS) # Skip over 'manage.py test' and any arguments handled by django. django_opts = ['--noinput', '--liveserver', '-p', '--pattern'] for opt in BaseCommand.option_list: django_opts.extend(opt._long_opts) django_opts.extend(opt._short_opts) nose_argv.extend(translate_option(opt) for opt in sys.argv[1:] if opt.startswith('-') and not any(opt.startswith(d) for d in django_opts)) # if --nose-verbosity was omitted, pass Django verbosity to nose if ('--verbosity' not in nose_argv and not any(opt.startswith('--verbosity=') for opt in nose_argv)): nose_argv.append('--verbosity=%s' % str(self.verbosity)) if self.verbosity >= 1: print(' '.join(nose_argv)) result = self.run_suite(nose_argv) # suite_result expects the suite as the first argument. Fake it. return self.suite_result({}, result) _old_handle = Command.handle def _foreign_key_ignoring_handle(self, *fixture_labels, **options): """Wrap the the stock loaddata to ignore foreign key checks so we can load circular references from fixtures. This is monkeypatched into place in setup_databases(). """ using = options.get('database', DEFAULT_DB_ALIAS) commit = options.get('commit', True) connection = connections[using] # MySQL stinks at loading circular references: if uses_mysql(connection): cursor = connection.cursor() cursor.execute('SET foreign_key_checks = 0') _old_handle(self, *fixture_labels, **options) if uses_mysql(connection): cursor = connection.cursor() cursor.execute('SET foreign_key_checks = 1') if commit: connection.close() def _skip_create_test_db(self, verbosity=1, autoclobber=False): """``create_test_db`` implementation that skips both creation and flushing The idea is to re-use the perfectly good test DB already created by an earlier test run, cutting the time spent before any tests run from 5-13s (depending on your I/O luck) down to 3. """ # Notice that the DB supports transactions. Originally, this was done in # the method this overrides. The confirm method was added in Django v1.3 # (https://code.djangoproject.com/ticket/12991) but removed in Django v1.5 # (https://code.djangoproject.com/ticket/17760). In Django v1.5 # supports_transactions is a cached property evaluated on access. if callable(getattr(self.connection.features, 'confirm', None)): # Django v1.3-4 self.connection.features.confirm() elif hasattr(self, "_rollback_works"): # Django v1.2 and lower can_rollback = self._rollback_works() self.connection.settings_dict['SUPPORTS_TRANSACTIONS'] = can_rollback return self._get_test_db_name() def _reusing_db(): """Return whether the ``REUSE_DB`` flag was passed""" return os.getenv('REUSE_DB', 'false').lower() in ('true', '1', '') def _can_support_reuse_db(connection): """Return whether it makes any sense to use REUSE_DB with the backend of a connection.""" # Perhaps this is a SQLite in-memory DB. Those are created implicitly when # you try to connect to them, so our usual test doesn't work. return not connection.creation._get_test_db_name() == ':memory:' def _should_create_database(connection): """Return whether we should recreate the given DB. This is true if the DB doesn't exist or the REUSE_DB env var isn't truthy. """ # TODO: Notice when the Model classes change and return True. Worst case, # we can generate sqlall and hash it, though it's a bit slow (2 secs) and # hits the DB for no good reason. Until we find a faster way, I'm inclined # to keep making people explicitly saying REUSE_DB if they want to reuse # the DB. if not _can_support_reuse_db(connection): return True # Notice whether the DB exists, and create it if it doesn't: try: connection.cursor() except Exception: # TODO: Be more discerning but still DB agnostic. return True return not _reusing_db() def _mysql_reset_sequences(style, connection): """Return a list of SQL statements needed to reset all sequences for Django tables.""" tables = connection.introspection.django_table_names(only_existing=True) flush_statements = connection.ops.sql_flush( style, tables, connection.introspection.sequence_list()) # connection.ops.sequence_reset_sql() is not implemented for MySQL, # and the base class just returns []. TODO: Implement it by pulling # the relevant bits out of sql_flush(). return [s for s in flush_statements if s.startswith('ALTER')] # Being overzealous and resetting the sequences on non-empty tables # like django_content_type seems to be fine in MySQL: adding a row # afterward does find the correct sequence number rather than # crashing into an existing row. class NoseTestSuiteRunner(BasicNoseRunner): """A runner that optionally skips DB creation Monkeypatches connection.creation to let you skip creating databases if they already exist. Your tests will start up much faster. To opt into this behavior, set the environment variable ``REUSE_DB`` to something that isn't "0" or "false" (case insensitive). """ def _get_models_for_connection(self, connection): """Return a list of models for a connection.""" tables = connection.introspection.get_table_list(connection.cursor()) return [m for m in models.loading.cache.get_models() if m._meta.db_table in tables] def setup_databases(self): for alias in connections: connection = connections[alias] creation = connection.creation test_db_name = creation._get_test_db_name() # Mess with the DB name so other things operate on a test DB # rather than the real one. This is done in create_test_db when # we don't monkeypatch it away with _skip_create_test_db. orig_db_name = connection.settings_dict['NAME'] connection.settings_dict['NAME'] = test_db_name if _should_create_database(connection): # We're not using _skip_create_test_db, so put the DB name # back: connection.settings_dict['NAME'] = orig_db_name # Since we replaced the connection with the test DB, closing # the connection will avoid pooling issues with SQLAlchemy. The # issue is trying to CREATE/DROP the test database using a # connection to a DB that was established with that test DB. # MySQLdb doesn't allow it, and SQLAlchemy attempts to reuse # the existing connection from its pool. connection.close() else: # Reset auto-increment sequences. Apparently, SUMO's tests are # horrid and coupled to certain numbers. cursor = connection.cursor() style = no_style() if uses_mysql(connection): reset_statements = _mysql_reset_sequences( style, connection) else: reset_statements = connection.ops.sequence_reset_sql( style, self._get_models_for_connection(connection)) for reset_statement in reset_statements: cursor.execute(reset_statement) # Django v1.3 (https://code.djangoproject.com/ticket/9964) # starts using commit_unless_managed() for individual # connections. Backwards compatibility for Django 1.2 is to use # the generic transaction function. transaction.commit_unless_managed(using=connection.alias) # Each connection has its own creation object, so this affects # only a single connection: creation.create_test_db = MethodType( _skip_create_test_db, creation, creation.__class__) Command.handle = _foreign_key_ignoring_handle # With our class patch, does nothing but return some connection # objects: return super(NoseTestSuiteRunner, self).setup_databases() def teardown_databases(self, *args, **kwargs): """Leave those poor, reusable databases alone if REUSE_DB is true.""" if not _reusing_db(): return super(NoseTestSuiteRunner, self).teardown_databases( *args, **kwargs) # else skip tearing down the DB so we can reuse it next time django-nose-1.2/django_nose/testcases.py0000644000076500000240000001560112124726631021156 0ustar jbaloghstaff00000000000000from django import test from django.conf import settings from django.core import cache, mail from django.core.management import call_command from django.db import connections, DEFAULT_DB_ALIAS, transaction from django_nose.fixture_tables import tables_used_by_fixtures from django_nose.utils import uses_mysql __all__ = ['FastFixtureTestCase'] class FastFixtureTestCase(test.TransactionTestCase): """Test case that loads fixtures once and for all rather than once per test Using this can save huge swaths of time while still preserving test isolation. Fixture data is loaded at class setup time, and the transaction is committed. Commit and rollback methods are then monkeypatched away (like in Django's standard TestCase), and each test is run. After each test, the monkeypatching is temporarily undone, and a rollback is issued, returning the DB content to the pristine fixture state. Finally, upon class teardown, the DB is restored to a post-syncdb-like state by deleting the contents of any table that had been touched by a fixture (keeping infrastructure tables like django_content_type and auth_permission intact). Note that this is like Django's TestCase, not its TransactionTestCase, in that you cannot do your own commits or rollbacks from within tests. For best speed, group tests using the same fixtures into as few classes as possible. Better still, don't do that, and instead use the fixture-bundling plugin from django-nose, which does it dynamically at test time. """ cleans_up_after_itself = True # This is the good kind of puppy. @classmethod def setUpClass(cls): """Turn on manual commits. Load and commit the fixtures.""" if not test.testcases.connections_support_transactions(): raise NotImplementedError('%s supports only DBs with transaction ' 'capabilities.' % cls.__name__) for db in cls._databases(): # These MUST be balanced with one leave_* each: transaction.enter_transaction_management(using=db) # Don't commit unless we say so: transaction.managed(True, using=db) cls._fixture_setup() @classmethod def tearDownClass(cls): """Truncate the world, and turn manual commit management back off.""" cls._fixture_teardown() for db in cls._databases(): # Finish off any transactions that may have happened in # tearDownClass in a child method. if transaction.is_dirty(using=db): transaction.commit(using=db) transaction.leave_transaction_management(using=db) @classmethod def _fixture_setup(cls): """Load fixture data, and commit.""" for db in cls._databases(): if (hasattr(cls, 'fixtures') and getattr(cls, '_fb_should_setup_fixtures', True)): # Iff the fixture-bundling test runner tells us we're the first # suite having these fixtures, set them up: call_command('loaddata', *cls.fixtures, **{'verbosity': 0, 'commit': False, 'database': db}) # No matter what, to preserve the effect of cursor start-up # statements... transaction.commit(using=db) @classmethod def _fixture_teardown(cls): """Empty (only) the tables we loaded fixtures into, then commit.""" if hasattr(cls, 'fixtures') and \ getattr(cls, '_fb_should_teardown_fixtures', True): # If the fixture-bundling test runner advises us that the next test # suite is going to reuse these fixtures, don't tear them down. for db in cls._databases(): tables = tables_used_by_fixtures(cls.fixtures, using=db) # TODO: Think about respecting _meta.db_tablespace, not just # db_table. if tables: connection = connections[db] cursor = connection.cursor() # TODO: Rather than assuming that anything added to by a # fixture can be emptied, remove only what the fixture # added. This would probably solve input.mozilla.com's # failures (since worked around) with Site objects; they # were loading additional Sites with a fixture, and then # the Django-provided example.com site was evaporating. if uses_mysql(connection): cursor.execute('SET FOREIGN_KEY_CHECKS=0') for table in tables: # Truncate implicitly commits. cursor.execute('TRUNCATE `%s`' % table) # TODO: necessary? cursor.execute('SET FOREIGN_KEY_CHECKS=1') else: for table in tables: cursor.execute('DELETE FROM %s' % table) transaction.commit(using=db) # cursor.close() # Should be unnecessary, since we committed # any environment-setup statements that come with opening a new # cursor when we committed the fixtures. def _pre_setup(self): """Disable transaction methods, and clear some globals.""" # Repeat stuff from TransactionTestCase, because I'm not calling its # _pre_setup, because that would load fixtures again. cache.cache.clear() settings.TEMPLATE_DEBUG = settings.DEBUG = False test.testcases.disable_transaction_methods() #self._fixture_setup() self._urlconf_setup() mail.outbox = [] # Clear site cache in case somebody's mutated Site objects and then # cached the mutated stuff: from django.contrib.sites.models import Site Site.objects.clear_cache() def _post_teardown(self): """Re-enable transaction methods, and roll back any changes. Rollback clears any DB changes made by the test so the original fixture data is again visible. """ # Rollback any mutations made by tests: test.testcases.restore_transaction_methods() for db in self._databases(): transaction.rollback(using=db) self._urlconf_teardown() # We do not need to close the connection here to prevent # http://code.djangoproject.com/ticket/7572, since we commit, not # rollback, the test fixtures and thus any cursor startup statements. # Don't call through to superclass, because that would call # _fixture_teardown() and close the connection. @classmethod def _databases(cls): if getattr(cls, 'multi_db', False): return connections else: return [DEFAULT_DB_ALIAS] django-nose-1.2/django_nose/tools.py0000644000076500000240000000315712124726631020323 0ustar jbaloghstaff00000000000000# vim: tabstop=4 expandtab autoindent shiftwidth=4 fileencoding=utf-8 """ Provides Nose and Django test case assert functions """ from django.test.testcases import TransactionTestCase from django.core import mail import re ## Python from nose import tools for t in dir(tools): if t.startswith('assert_'): vars()[t] = getattr(tools, t) ## Django caps = re.compile('([A-Z])') def pep8(name): return caps.sub(lambda m: '_' + m.groups()[0].lower(), name) class Dummy(TransactionTestCase): def nop(): pass _t = Dummy('nop') for at in [ at for at in dir(_t) if at.startswith('assert') and not '_' in at ]: pepd = pep8(at) vars()[pepd] = getattr(_t, at) del Dummy del _t del pep8 ## New def assert_code(response, status_code, msg_prefix=''): """Asserts the response was returned with the given status code """ if msg_prefix: msg_prefix = '%s: ' % msg_prefix assert response.status_code == status_code, \ 'Response code was %d (expected %d)' % \ (response.status_code, status_code) def assert_ok(response, msg_prefix=''): """Asserts the response was returned with status 200 (OK) """ return assert_code(response, 200, msg_prefix=msg_prefix) def assert_mail_count(count, msg=None): """Assert the number of emails sent. The message here tends to be long, so allow for replacing the whole thing instead of prefixing. """ if msg is None: msg = ', '.join([e.subject for e in mail.outbox]) msg = '%d != %d %s' % (len(mail.outbox), count, msg) assert_equals(len(mail.outbox), count, msg) # EOF django-nose-1.2/django_nose/utils.py0000644000076500000240000000350512124726631020320 0ustar jbaloghstaff00000000000000def process_tests(suite, process): """Given a nested disaster of [Lazy]Suites, traverse to the first level that has setup or teardown, and do something to them. If we were to traverse all the way to the leaves (the Tests) indiscriminately and return them, when the runner later calls them, they'd run without reference to the suite that contained them, so they'd miss their class-, module-, and package-wide setup and teardown routines. The nested suites form basically a double-linked tree, and suites will call up to their containing suites to run their setups and teardowns, but it would be hubris to assume that something you saw fit to setup or teardown at the module level is less costly to repeat than DB fixtures. Also, those sorts of setups and teardowns are extremely rare in our code. Thus, we limit the granularity of bucketing to the first level that has setups or teardowns. :arg process: The thing to call once we get to a leaf or a test with setup or teardown """ if (not hasattr(suite, '_tests') or (hasattr(suite, 'hasFixtures') and suite.hasFixtures())): # We hit a Test or something with setup, so do the thing. (Note that # "fixtures" here means setup or teardown routines, not Django # fixtures.) process(suite) else: for t in suite._tests: process_tests(t, process) def is_subclass_at_all(cls, class_info): """Return whether ``cls`` is a subclass of ``class_info``. Even if ``cls`` is not a class, don't crash. Return False instead. """ try: return issubclass(cls, class_info) except TypeError: return False def uses_mysql(connection): """Return whether the connection represents a MySQL DB.""" return 'mysql' in connection.settings_dict['ENGINE'] django-nose-1.2/django_nose.egg-info/0000755000076500000240000000000012173536173020301 5ustar jbaloghstaff00000000000000django-nose-1.2/django_nose.egg-info/dependency_links.txt0000644000076500000240000000000112173536173024347 0ustar jbaloghstaff00000000000000 django-nose-1.2/django_nose.egg-info/not-zip-safe0000644000076500000240000000000112173536120022517 0ustar jbaloghstaff00000000000000 django-nose-1.2/django_nose.egg-info/PKG-INFO0000644000076500000240000004220512173536173021401 0ustar jbaloghstaff00000000000000Metadata-Version: 1.1 Name: django-nose Version: 1.2 Summary: Makes your Django tests simple and snappy Home-page: http://github.com/jbalogh/django-nose Author: Erik Rose Author-email: erikrose@grinchcentral.com License: BSD Description: =========== django-nose =========== .. image:: https://travis-ci.org/jbalogh/django-nose.png :target: https://travis-ci.org/jbalogh/django-nose Features -------- * All the goodness of `nose`_ in your Django tests, like... * Testing just your apps by default, not all the standard ones that happen to be in ``INSTALLED_APPS`` * Running the tests in one or more specific modules (or apps, or classes, or folders, or just running a specific test) * Obviating the need to import all your tests into ``tests/__init__.py``. This not only saves busy-work but also eliminates the possibility of accidentally shadowing test classes. * Taking advantage of all the useful `nose plugins`_ * Fixture bundling, an optional feature which speeds up your fixture-based tests by a factor of 4 * Reuse of previously created test DBs, cutting 10 seconds off startup time * Hygienic TransactionTestCases, which can save you a DB flush per test * Support for various databases. Tested with MySQL, PostgreSQL, and SQLite. Others should work as well. .. _nose: http://somethingaboutorange.com/mrl/projects/nose/ .. _nose plugins: http://nose-plugins.jottit.com/ Installation ------------ You can get django-nose from PyPI with... :: pip install django-nose The development version can be installed with... :: pip install -e git://github.com/jbalogh/django-nose.git#egg=django-nose Since django-nose extends Django's built-in test command, you should add it to your ``INSTALLED_APPS`` in ``settings.py``:: INSTALLED_APPS = ( ... 'django_nose', ... ) Then set ``TEST_RUNNER`` in ``settings.py``:: TEST_RUNNER = 'django_nose.NoseTestSuiteRunner' Use --- The day-to-day use of django-nose is mostly transparent; just run ``./manage.py test`` as usual. See ``./manage.py help test`` for all the options nose provides, and look to the `nose docs`_ for more help with nose. .. _nose docs: http://somethingaboutorange.com/mrl/projects/nose/ Enabling Database Reuse ----------------------- You can save several seconds at the beginning and end of your test suite by reusing the test database from the last run. To do this, set the environment variable ``REUSE_DB`` to 1:: REUSE_DB=1 ./manage.py test The one new wrinkle is that, whenever your DB schema changes, you should leave the flag off the next time you run tests. This will cue the test runner to reinitialize the test database. Also, REUSE_DB is not compatible with TransactionTestCases that leave junk in the DB, so be sure to make your TransactionTestCases hygienic (see below) if you want to use it. Enabling Fast Fixtures ---------------------- django-nose includes a fixture bundler which drastically speeds up your tests by eliminating redundant setup of Django test fixtures. To use it... 1. Subclass ``django_nose.FastFixtureTestCase`` instead of ``django.test.TestCase``. (I like to import it ``as TestCase`` in my project's ``tests/__init__.py`` and then import it from there into my actual tests. Then it's easy to sub the base class in and out.) This alone will cause fixtures to load once per class rather than once per test. 2. Activate fixture bundling by passing the ``--with-fixture-bundling`` option to ``./manage.py test``. This loads each unique set of fixtures only once, even across class, module, and app boundaries. How Fixture Bundling Works ~~~~~~~~~~~~~~~~~~~~~~~~~~ The fixture bundler reorders your test classes so that ones with identical sets of fixtures run adjacently. It then advises the first of each series to load the fixtures once for all of them (and the remaining ones not to bother). It also advises the last to tear them down. Depending on the size and repetition of your fixtures, you can expect a 25% to 50% speed increase. Incidentally, the author prefers to avoid Django fixtures, as they encourage irrelevant coupling between tests and make tests harder to comprehend and modify. For future tests, it is better to use the "model maker" pattern, creating DB objects programmatically. This way, tests avoid setup they don't need, and there is a clearer tie between a test and the exact state it requires. The fixture bundler is intended to make existing tests, which have already committed to fixtures, more tolerable. Troubleshooting ~~~~~~~~~~~~~~~ If using ``--with-fixture-bundling`` causes test failures, it likely indicates an order dependency between some of your tests. Here are the most frequent sources of state leakage we have encountered: * Locale activation, which is maintained in a threadlocal variable. Be sure to reset your locale selection between tests. * memcached contents. Be sure to flush between tests. Many test superclasses do this automatically. It's also possible that you have ``post_save`` signal handlers which create additional database rows while loading the fixtures. ``FastFixtureTestCase`` isn't yet smart enough to notice this and clean up after it, so you'll have to go back to plain old ``TestCase`` for now. Exempting A Class From Bundling ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In some unusual cases, it is desirable to exempt a test class from fixture bundling, forcing it to set up and tear down its fixtures at the class boundaries. For example, we might have a ``TestCase`` subclass which sets up some state outside the DB in ``setUpClass`` and tears it down in ``tearDownClass``, and it might not be possible to adapt those routines to heed the advice of the fixture bundler. In such a case, simply set the ``exempt_from_fixture_bundling`` attribute of the test class to ``True``. Speedy Hygienic TransactionTestCases ------------------------------------ Unlike the stock Django test runner, django-nose lets you write custom TransactionTestCase subclasses which expect to start with an unmarred DB, saving an entire DB flush per test. Background ~~~~~~~~~~ The default Django TransactionTestCase class `can leave the DB in an unclean state`_ when it's done. To compensate, TransactionTestCase does a time-consuming flush of the DB *before* each test to ensure it begins with a clean slate. Django's stock test runner then runs TransactionTestCases last so they don't wreck the environment for better-behaved tests. django-nose replicates this behavior. Escaping the Grime ~~~~~~~~~~~~~~~~~~ Some people, however, have made subclasses of TransactionTestCase that clean up after themselves (and can do so efficiently, since they know what they've changed). Like TestCase, these may assume they start with a clean DB. However, any TransactionTestCases that run before them and leave a mess could cause them to fail spuriously. django-nose offers to fix this. If you include a special attribute on your well-behaved TransactionTestCase... :: class MyNiceTestCase(TransactionTestCase): cleans_up_after_itself = True ...django-nose will run it before any of those nasty, trash-spewing test cases. You can thus enjoy a big speed boost any time you make a TransactionTestCase clean up after itself: skipping a whole DB flush before every test. With a large schema, this can save minutes of IO. django-nose's own FastFixtureTestCase uses this feature, even though it ultimately acts more like a TestCase than a TransactionTestCase. .. _can leave the DB in an unclean state: https://docs.djangoproject.com/en/1.4/topics/testing/#django.test.TransactionTestCase Test-Only Models ---------------- If you have a model that is used only by tests (for example, to test an abstract model base class), you can put it in any file that's imported in the course of loading tests. For example, if the tests that need it are in ``test_models.py``, you can put the model in there, too. django-nose will make sure its DB table gets created. Assertions ---------- ``django-nose.tools`` provides pep8 versions of Django's TestCase asserts and some of its own as functions. :: assert_redirects(response, expected_url, status_code=302, target_status_code=200, host=None, msg_prefix='') assert_contains(response, text, count=None, status_code=200, msg_prefix='') assert_not_contains(response, text, count=None, status_code=200, msg_prefix='') assert_form_error(response, form, field, errors, msg_prefix='') assert_template_used(response, template_name, msg_prefix='') assert_template_not_used(response, template_name, msg_prefix='') assert_queryset_equal(qs, values, transform=repr) assert_num_queries(num, func=None, *args, **kwargs) assert_code(response, status_code, msg_prefix='') assert_ok(response, msg_prefix='') assert_mail_count(count, msg=None) Using With South ---------------- `South`_ installs its own test command that turns off migrations during testing. Make sure that django-nose comes *after* ``south`` in ``INSTALLED_APPS`` so that django_nose's test command is used. .. _South: http://south.aeracode.org/ Always Passing The Same Options ------------------------------- To always set the same command line options you can use a `nose.cfg or setup.cfg`_ (as usual) or you can specify them in settings.py like this:: NOSE_ARGS = ['--failed', '--stop'] .. _nose.cfg or setup.cfg: http://somethingaboutorange.com/mrl/projects/nose/0.11.2/usage.html#configuration Custom Plugins -------------- If you need to `make custom plugins`_, you can define each plugin class somewhere within your app and load them from settings.py like this:: NOSE_PLUGINS = [ 'yourapp.tests.plugins.SystematicDysfunctioner', # ... ] Just like middleware or anything else, each string must be a dot-separated, importable path to an actual class. Each plugin class will be instantiated and added to the Nose test runner. .. _make custom plugins: http://somethingaboutorange.com/mrl/projects/nose/0.11.2/plugins.html#writing-plugins Older Versions of Django ------------------------ Upgrading from Django <= 1.3 to Django 1.4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In versions of Django < 1.4 the project folder was in fact a python package as well (note the __init__.py in your project root). In Django 1.4, there is no such file and thus the project is not a python module. **When you upgrade your Django project to the Django 1.4 layout, you need to remove the __init__.py file in the root of your project (and move any python files that reside there other than the manage.py) otherwise you will get a `ImportError: No module named urls` exception.** This happens because Nose will intelligently try to populate your sys.path, and in this particular case includes your parent directory if your project has a __init__.py file (see: https://github.com/nose-devs/nose/blob/release_1.1.2/nose/importer.py#L134). This means that even though you have set up your directory structure properly and set your `ROOT_URLCONF='my_project.urls'` to match the new structure, when running django-nose's test runner it will try to find your urls.py file in `'my_project.my_project.urls'`. Upgrading from Django < 1.2 ~~~~~~~~~~~~~~~~~~~~~~~~~~~ Django 1.2 switches to a `class-based test runner`_. To use django-nose with Django 1.2, change your ``TEST_RUNNER`` from ``django_nose.run_tests`` to ``django_nose.NoseTestSuiteRunner``. ``django_nose.run_tests`` will continue to work in Django 1.2 but will raise a warning. In Django 1.3, it will stop working. If you were using ``django_nose.run_gis_tests``, you should also switch to ``django_nose.NoseTestSuiteRunner`` and use one of the `spatial backends`_ in your ``DATABASES`` settings. .. _class-based test runner: http://docs.djangoproject.com/en/dev/releases/1.2/#function-based-test-runners .. _spatial backends: http://docs.djangoproject.com/en/dev/ref/contrib/gis/db-api/#id1 Django 1.1 ~~~~~~~~~~ If you want to use django-nose with Django 1.1, use https://github.com/jbalogh/django-nose/tree/django-1.1 or http://pypi.python.org/pypi/django-nose/0.0.3. Django 1.0 ~~~~~~~~~~ django-nose does not support Django 1.0. Recent Version History ---------------------- 1.1 (2012-05-19) * Django TransactionTestCases don't clean up after themselves; they leave junk in the DB and clean it up only on ``_pre_setup``. Thus, Django makes sure these tests run last. Now django-nose does, too. This means one fewer source of failures on existing projects. (Erik Rose) * Add support for hygienic TransactionTestCases. (Erik Rose) * Support models that are used only for tests. Just put them in any file imported in the course of loading tests. No more crazy hacks necessary. (Erik Rose) * Make the fixture bundler more conservative, fixing some conceivable situations in which fixtures would not appear as intended if a TransactionTestCase found its way into the middle of a bundle. (Erik Rose) * Fix an error that would surface when using SQLAlchemy with connection pooling. (Roger Hu) * Gracefully ignore the new ``--liveserver`` option introduced in Django 1.4; don't let it through to nose. (Adam DePue) 1.0 (2012-03-12) * New fixture-bundling plugin for avoiding needless fixture setup (Erik Rose) * Moved FastFixtureTestCase in from test-utils, so now all the fixture-bundling stuff is in one library. (Erik Rose) * Added the REUSE_DB setting for faster startup and shutdown. (Erik Rose) * Fixed a crash when printing options with certain verbosities. (Daniel Abel) * Broke hard dependency on MySQL. Support PostgreSQL. (Roger Hu) * Support SQLite, both memory- and disk-based. (Roger Hu and Erik Rose) * Nail down versions of the package requirements. (Daniel Mizyrycki) 0.1.3 (2010-04-15) * Even better coverage support (rozza) * README fixes (carljm and ionelmc) * optparse OptionGroups are handled better (outofculture) * nose plugins are loaded before listing options See more in changelog.txt. Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Environment :: Web Environment Classifier: Framework :: Django Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: BSD License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3.3 Classifier: Topic :: Software Development :: Testing django-nose-1.2/django_nose.egg-info/requires.txt0000644000076500000240000000002712173536173022700 0ustar jbaloghstaff00000000000000nose>=1.2.1 Django>=1.2django-nose-1.2/django_nose.egg-info/SOURCES.txt0000644000076500000240000000146312173536173022171 0ustar jbaloghstaff00000000000000LICENSE MANIFEST.in README.rst changelog.txt runtests.sh setup.py django_nose/__init__.py django_nose/fixture_tables.py django_nose/plugin.py django_nose/runner.py django_nose/testcases.py django_nose/tools.py django_nose/utils.py django_nose.egg-info/PKG-INFO django_nose.egg-info/SOURCES.txt django_nose.egg-info/dependency_links.txt django_nose.egg-info/not-zip-safe django_nose.egg-info/requires.txt django_nose.egg-info/top_level.txt django_nose/management/__init__.py django_nose/management/commands/__init__.py django_nose/management/commands/test.py testapp/__init__.py testapp/plugins.py testapp/runtests.py testapp/settings.py testapp/settings_old_style.py testapp/settings_with_plugins.py testapp/settings_with_south.py testapp/test_for_nose.py testapp/test_only_this.py testapp/plugin_t/test_with_plugins.pydjango-nose-1.2/django_nose.egg-info/top_level.txt0000644000076500000240000000001412173536173023026 0ustar jbaloghstaff00000000000000django_nose django-nose-1.2/LICENSE0000644000076500000240000000276012124726631015327 0ustar jbaloghstaff00000000000000Copyright (c) 2010, Jeff Balogh. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of django-nose nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. django-nose-1.2/MANIFEST.in0000644000076500000240000000026312124726631016054 0ustar jbaloghstaff00000000000000include LICENSE include README.rst include runtests.sh include changelog.txt recursive-exclude django_nose *.py[co] recursive-include testapp * recursive-exclude testapp *.py[co] django-nose-1.2/PKG-INFO0000644000076500000240000004220512173536173015421 0ustar jbaloghstaff00000000000000Metadata-Version: 1.1 Name: django-nose Version: 1.2 Summary: Makes your Django tests simple and snappy Home-page: http://github.com/jbalogh/django-nose Author: Erik Rose Author-email: erikrose@grinchcentral.com License: BSD Description: =========== django-nose =========== .. image:: https://travis-ci.org/jbalogh/django-nose.png :target: https://travis-ci.org/jbalogh/django-nose Features -------- * All the goodness of `nose`_ in your Django tests, like... * Testing just your apps by default, not all the standard ones that happen to be in ``INSTALLED_APPS`` * Running the tests in one or more specific modules (or apps, or classes, or folders, or just running a specific test) * Obviating the need to import all your tests into ``tests/__init__.py``. This not only saves busy-work but also eliminates the possibility of accidentally shadowing test classes. * Taking advantage of all the useful `nose plugins`_ * Fixture bundling, an optional feature which speeds up your fixture-based tests by a factor of 4 * Reuse of previously created test DBs, cutting 10 seconds off startup time * Hygienic TransactionTestCases, which can save you a DB flush per test * Support for various databases. Tested with MySQL, PostgreSQL, and SQLite. Others should work as well. .. _nose: http://somethingaboutorange.com/mrl/projects/nose/ .. _nose plugins: http://nose-plugins.jottit.com/ Installation ------------ You can get django-nose from PyPI with... :: pip install django-nose The development version can be installed with... :: pip install -e git://github.com/jbalogh/django-nose.git#egg=django-nose Since django-nose extends Django's built-in test command, you should add it to your ``INSTALLED_APPS`` in ``settings.py``:: INSTALLED_APPS = ( ... 'django_nose', ... ) Then set ``TEST_RUNNER`` in ``settings.py``:: TEST_RUNNER = 'django_nose.NoseTestSuiteRunner' Use --- The day-to-day use of django-nose is mostly transparent; just run ``./manage.py test`` as usual. See ``./manage.py help test`` for all the options nose provides, and look to the `nose docs`_ for more help with nose. .. _nose docs: http://somethingaboutorange.com/mrl/projects/nose/ Enabling Database Reuse ----------------------- You can save several seconds at the beginning and end of your test suite by reusing the test database from the last run. To do this, set the environment variable ``REUSE_DB`` to 1:: REUSE_DB=1 ./manage.py test The one new wrinkle is that, whenever your DB schema changes, you should leave the flag off the next time you run tests. This will cue the test runner to reinitialize the test database. Also, REUSE_DB is not compatible with TransactionTestCases that leave junk in the DB, so be sure to make your TransactionTestCases hygienic (see below) if you want to use it. Enabling Fast Fixtures ---------------------- django-nose includes a fixture bundler which drastically speeds up your tests by eliminating redundant setup of Django test fixtures. To use it... 1. Subclass ``django_nose.FastFixtureTestCase`` instead of ``django.test.TestCase``. (I like to import it ``as TestCase`` in my project's ``tests/__init__.py`` and then import it from there into my actual tests. Then it's easy to sub the base class in and out.) This alone will cause fixtures to load once per class rather than once per test. 2. Activate fixture bundling by passing the ``--with-fixture-bundling`` option to ``./manage.py test``. This loads each unique set of fixtures only once, even across class, module, and app boundaries. How Fixture Bundling Works ~~~~~~~~~~~~~~~~~~~~~~~~~~ The fixture bundler reorders your test classes so that ones with identical sets of fixtures run adjacently. It then advises the first of each series to load the fixtures once for all of them (and the remaining ones not to bother). It also advises the last to tear them down. Depending on the size and repetition of your fixtures, you can expect a 25% to 50% speed increase. Incidentally, the author prefers to avoid Django fixtures, as they encourage irrelevant coupling between tests and make tests harder to comprehend and modify. For future tests, it is better to use the "model maker" pattern, creating DB objects programmatically. This way, tests avoid setup they don't need, and there is a clearer tie between a test and the exact state it requires. The fixture bundler is intended to make existing tests, which have already committed to fixtures, more tolerable. Troubleshooting ~~~~~~~~~~~~~~~ If using ``--with-fixture-bundling`` causes test failures, it likely indicates an order dependency between some of your tests. Here are the most frequent sources of state leakage we have encountered: * Locale activation, which is maintained in a threadlocal variable. Be sure to reset your locale selection between tests. * memcached contents. Be sure to flush between tests. Many test superclasses do this automatically. It's also possible that you have ``post_save`` signal handlers which create additional database rows while loading the fixtures. ``FastFixtureTestCase`` isn't yet smart enough to notice this and clean up after it, so you'll have to go back to plain old ``TestCase`` for now. Exempting A Class From Bundling ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In some unusual cases, it is desirable to exempt a test class from fixture bundling, forcing it to set up and tear down its fixtures at the class boundaries. For example, we might have a ``TestCase`` subclass which sets up some state outside the DB in ``setUpClass`` and tears it down in ``tearDownClass``, and it might not be possible to adapt those routines to heed the advice of the fixture bundler. In such a case, simply set the ``exempt_from_fixture_bundling`` attribute of the test class to ``True``. Speedy Hygienic TransactionTestCases ------------------------------------ Unlike the stock Django test runner, django-nose lets you write custom TransactionTestCase subclasses which expect to start with an unmarred DB, saving an entire DB flush per test. Background ~~~~~~~~~~ The default Django TransactionTestCase class `can leave the DB in an unclean state`_ when it's done. To compensate, TransactionTestCase does a time-consuming flush of the DB *before* each test to ensure it begins with a clean slate. Django's stock test runner then runs TransactionTestCases last so they don't wreck the environment for better-behaved tests. django-nose replicates this behavior. Escaping the Grime ~~~~~~~~~~~~~~~~~~ Some people, however, have made subclasses of TransactionTestCase that clean up after themselves (and can do so efficiently, since they know what they've changed). Like TestCase, these may assume they start with a clean DB. However, any TransactionTestCases that run before them and leave a mess could cause them to fail spuriously. django-nose offers to fix this. If you include a special attribute on your well-behaved TransactionTestCase... :: class MyNiceTestCase(TransactionTestCase): cleans_up_after_itself = True ...django-nose will run it before any of those nasty, trash-spewing test cases. You can thus enjoy a big speed boost any time you make a TransactionTestCase clean up after itself: skipping a whole DB flush before every test. With a large schema, this can save minutes of IO. django-nose's own FastFixtureTestCase uses this feature, even though it ultimately acts more like a TestCase than a TransactionTestCase. .. _can leave the DB in an unclean state: https://docs.djangoproject.com/en/1.4/topics/testing/#django.test.TransactionTestCase Test-Only Models ---------------- If you have a model that is used only by tests (for example, to test an abstract model base class), you can put it in any file that's imported in the course of loading tests. For example, if the tests that need it are in ``test_models.py``, you can put the model in there, too. django-nose will make sure its DB table gets created. Assertions ---------- ``django-nose.tools`` provides pep8 versions of Django's TestCase asserts and some of its own as functions. :: assert_redirects(response, expected_url, status_code=302, target_status_code=200, host=None, msg_prefix='') assert_contains(response, text, count=None, status_code=200, msg_prefix='') assert_not_contains(response, text, count=None, status_code=200, msg_prefix='') assert_form_error(response, form, field, errors, msg_prefix='') assert_template_used(response, template_name, msg_prefix='') assert_template_not_used(response, template_name, msg_prefix='') assert_queryset_equal(qs, values, transform=repr) assert_num_queries(num, func=None, *args, **kwargs) assert_code(response, status_code, msg_prefix='') assert_ok(response, msg_prefix='') assert_mail_count(count, msg=None) Using With South ---------------- `South`_ installs its own test command that turns off migrations during testing. Make sure that django-nose comes *after* ``south`` in ``INSTALLED_APPS`` so that django_nose's test command is used. .. _South: http://south.aeracode.org/ Always Passing The Same Options ------------------------------- To always set the same command line options you can use a `nose.cfg or setup.cfg`_ (as usual) or you can specify them in settings.py like this:: NOSE_ARGS = ['--failed', '--stop'] .. _nose.cfg or setup.cfg: http://somethingaboutorange.com/mrl/projects/nose/0.11.2/usage.html#configuration Custom Plugins -------------- If you need to `make custom plugins`_, you can define each plugin class somewhere within your app and load them from settings.py like this:: NOSE_PLUGINS = [ 'yourapp.tests.plugins.SystematicDysfunctioner', # ... ] Just like middleware or anything else, each string must be a dot-separated, importable path to an actual class. Each plugin class will be instantiated and added to the Nose test runner. .. _make custom plugins: http://somethingaboutorange.com/mrl/projects/nose/0.11.2/plugins.html#writing-plugins Older Versions of Django ------------------------ Upgrading from Django <= 1.3 to Django 1.4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In versions of Django < 1.4 the project folder was in fact a python package as well (note the __init__.py in your project root). In Django 1.4, there is no such file and thus the project is not a python module. **When you upgrade your Django project to the Django 1.4 layout, you need to remove the __init__.py file in the root of your project (and move any python files that reside there other than the manage.py) otherwise you will get a `ImportError: No module named urls` exception.** This happens because Nose will intelligently try to populate your sys.path, and in this particular case includes your parent directory if your project has a __init__.py file (see: https://github.com/nose-devs/nose/blob/release_1.1.2/nose/importer.py#L134). This means that even though you have set up your directory structure properly and set your `ROOT_URLCONF='my_project.urls'` to match the new structure, when running django-nose's test runner it will try to find your urls.py file in `'my_project.my_project.urls'`. Upgrading from Django < 1.2 ~~~~~~~~~~~~~~~~~~~~~~~~~~~ Django 1.2 switches to a `class-based test runner`_. To use django-nose with Django 1.2, change your ``TEST_RUNNER`` from ``django_nose.run_tests`` to ``django_nose.NoseTestSuiteRunner``. ``django_nose.run_tests`` will continue to work in Django 1.2 but will raise a warning. In Django 1.3, it will stop working. If you were using ``django_nose.run_gis_tests``, you should also switch to ``django_nose.NoseTestSuiteRunner`` and use one of the `spatial backends`_ in your ``DATABASES`` settings. .. _class-based test runner: http://docs.djangoproject.com/en/dev/releases/1.2/#function-based-test-runners .. _spatial backends: http://docs.djangoproject.com/en/dev/ref/contrib/gis/db-api/#id1 Django 1.1 ~~~~~~~~~~ If you want to use django-nose with Django 1.1, use https://github.com/jbalogh/django-nose/tree/django-1.1 or http://pypi.python.org/pypi/django-nose/0.0.3. Django 1.0 ~~~~~~~~~~ django-nose does not support Django 1.0. Recent Version History ---------------------- 1.1 (2012-05-19) * Django TransactionTestCases don't clean up after themselves; they leave junk in the DB and clean it up only on ``_pre_setup``. Thus, Django makes sure these tests run last. Now django-nose does, too. This means one fewer source of failures on existing projects. (Erik Rose) * Add support for hygienic TransactionTestCases. (Erik Rose) * Support models that are used only for tests. Just put them in any file imported in the course of loading tests. No more crazy hacks necessary. (Erik Rose) * Make the fixture bundler more conservative, fixing some conceivable situations in which fixtures would not appear as intended if a TransactionTestCase found its way into the middle of a bundle. (Erik Rose) * Fix an error that would surface when using SQLAlchemy with connection pooling. (Roger Hu) * Gracefully ignore the new ``--liveserver`` option introduced in Django 1.4; don't let it through to nose. (Adam DePue) 1.0 (2012-03-12) * New fixture-bundling plugin for avoiding needless fixture setup (Erik Rose) * Moved FastFixtureTestCase in from test-utils, so now all the fixture-bundling stuff is in one library. (Erik Rose) * Added the REUSE_DB setting for faster startup and shutdown. (Erik Rose) * Fixed a crash when printing options with certain verbosities. (Daniel Abel) * Broke hard dependency on MySQL. Support PostgreSQL. (Roger Hu) * Support SQLite, both memory- and disk-based. (Roger Hu and Erik Rose) * Nail down versions of the package requirements. (Daniel Mizyrycki) 0.1.3 (2010-04-15) * Even better coverage support (rozza) * README fixes (carljm and ionelmc) * optparse OptionGroups are handled better (outofculture) * nose plugins are loaded before listing options See more in changelog.txt. Platform: UNKNOWN Classifier: Development Status :: 5 - Production/Stable Classifier: Environment :: Web Environment Classifier: Framework :: Django Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: BSD License Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.6 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3.3 Classifier: Topic :: Software Development :: Testing django-nose-1.2/README.rst0000644000076500000240000003304512124740666016015 0ustar jbaloghstaff00000000000000=========== django-nose =========== .. image:: https://travis-ci.org/jbalogh/django-nose.png :target: https://travis-ci.org/jbalogh/django-nose Features -------- * All the goodness of `nose`_ in your Django tests, like... * Testing just your apps by default, not all the standard ones that happen to be in ``INSTALLED_APPS`` * Running the tests in one or more specific modules (or apps, or classes, or folders, or just running a specific test) * Obviating the need to import all your tests into ``tests/__init__.py``. This not only saves busy-work but also eliminates the possibility of accidentally shadowing test classes. * Taking advantage of all the useful `nose plugins`_ * Fixture bundling, an optional feature which speeds up your fixture-based tests by a factor of 4 * Reuse of previously created test DBs, cutting 10 seconds off startup time * Hygienic TransactionTestCases, which can save you a DB flush per test * Support for various databases. Tested with MySQL, PostgreSQL, and SQLite. Others should work as well. .. _nose: http://somethingaboutorange.com/mrl/projects/nose/ .. _nose plugins: http://nose-plugins.jottit.com/ Installation ------------ You can get django-nose from PyPI with... :: pip install django-nose The development version can be installed with... :: pip install -e git://github.com/jbalogh/django-nose.git#egg=django-nose Since django-nose extends Django's built-in test command, you should add it to your ``INSTALLED_APPS`` in ``settings.py``:: INSTALLED_APPS = ( ... 'django_nose', ... ) Then set ``TEST_RUNNER`` in ``settings.py``:: TEST_RUNNER = 'django_nose.NoseTestSuiteRunner' Use --- The day-to-day use of django-nose is mostly transparent; just run ``./manage.py test`` as usual. See ``./manage.py help test`` for all the options nose provides, and look to the `nose docs`_ for more help with nose. .. _nose docs: http://somethingaboutorange.com/mrl/projects/nose/ Enabling Database Reuse ----------------------- You can save several seconds at the beginning and end of your test suite by reusing the test database from the last run. To do this, set the environment variable ``REUSE_DB`` to 1:: REUSE_DB=1 ./manage.py test The one new wrinkle is that, whenever your DB schema changes, you should leave the flag off the next time you run tests. This will cue the test runner to reinitialize the test database. Also, REUSE_DB is not compatible with TransactionTestCases that leave junk in the DB, so be sure to make your TransactionTestCases hygienic (see below) if you want to use it. Enabling Fast Fixtures ---------------------- django-nose includes a fixture bundler which drastically speeds up your tests by eliminating redundant setup of Django test fixtures. To use it... 1. Subclass ``django_nose.FastFixtureTestCase`` instead of ``django.test.TestCase``. (I like to import it ``as TestCase`` in my project's ``tests/__init__.py`` and then import it from there into my actual tests. Then it's easy to sub the base class in and out.) This alone will cause fixtures to load once per class rather than once per test. 2. Activate fixture bundling by passing the ``--with-fixture-bundling`` option to ``./manage.py test``. This loads each unique set of fixtures only once, even across class, module, and app boundaries. How Fixture Bundling Works ~~~~~~~~~~~~~~~~~~~~~~~~~~ The fixture bundler reorders your test classes so that ones with identical sets of fixtures run adjacently. It then advises the first of each series to load the fixtures once for all of them (and the remaining ones not to bother). It also advises the last to tear them down. Depending on the size and repetition of your fixtures, you can expect a 25% to 50% speed increase. Incidentally, the author prefers to avoid Django fixtures, as they encourage irrelevant coupling between tests and make tests harder to comprehend and modify. For future tests, it is better to use the "model maker" pattern, creating DB objects programmatically. This way, tests avoid setup they don't need, and there is a clearer tie between a test and the exact state it requires. The fixture bundler is intended to make existing tests, which have already committed to fixtures, more tolerable. Troubleshooting ~~~~~~~~~~~~~~~ If using ``--with-fixture-bundling`` causes test failures, it likely indicates an order dependency between some of your tests. Here are the most frequent sources of state leakage we have encountered: * Locale activation, which is maintained in a threadlocal variable. Be sure to reset your locale selection between tests. * memcached contents. Be sure to flush between tests. Many test superclasses do this automatically. It's also possible that you have ``post_save`` signal handlers which create additional database rows while loading the fixtures. ``FastFixtureTestCase`` isn't yet smart enough to notice this and clean up after it, so you'll have to go back to plain old ``TestCase`` for now. Exempting A Class From Bundling ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In some unusual cases, it is desirable to exempt a test class from fixture bundling, forcing it to set up and tear down its fixtures at the class boundaries. For example, we might have a ``TestCase`` subclass which sets up some state outside the DB in ``setUpClass`` and tears it down in ``tearDownClass``, and it might not be possible to adapt those routines to heed the advice of the fixture bundler. In such a case, simply set the ``exempt_from_fixture_bundling`` attribute of the test class to ``True``. Speedy Hygienic TransactionTestCases ------------------------------------ Unlike the stock Django test runner, django-nose lets you write custom TransactionTestCase subclasses which expect to start with an unmarred DB, saving an entire DB flush per test. Background ~~~~~~~~~~ The default Django TransactionTestCase class `can leave the DB in an unclean state`_ when it's done. To compensate, TransactionTestCase does a time-consuming flush of the DB *before* each test to ensure it begins with a clean slate. Django's stock test runner then runs TransactionTestCases last so they don't wreck the environment for better-behaved tests. django-nose replicates this behavior. Escaping the Grime ~~~~~~~~~~~~~~~~~~ Some people, however, have made subclasses of TransactionTestCase that clean up after themselves (and can do so efficiently, since they know what they've changed). Like TestCase, these may assume they start with a clean DB. However, any TransactionTestCases that run before them and leave a mess could cause them to fail spuriously. django-nose offers to fix this. If you include a special attribute on your well-behaved TransactionTestCase... :: class MyNiceTestCase(TransactionTestCase): cleans_up_after_itself = True ...django-nose will run it before any of those nasty, trash-spewing test cases. You can thus enjoy a big speed boost any time you make a TransactionTestCase clean up after itself: skipping a whole DB flush before every test. With a large schema, this can save minutes of IO. django-nose's own FastFixtureTestCase uses this feature, even though it ultimately acts more like a TestCase than a TransactionTestCase. .. _can leave the DB in an unclean state: https://docs.djangoproject.com/en/1.4/topics/testing/#django.test.TransactionTestCase Test-Only Models ---------------- If you have a model that is used only by tests (for example, to test an abstract model base class), you can put it in any file that's imported in the course of loading tests. For example, if the tests that need it are in ``test_models.py``, you can put the model in there, too. django-nose will make sure its DB table gets created. Assertions ---------- ``django-nose.tools`` provides pep8 versions of Django's TestCase asserts and some of its own as functions. :: assert_redirects(response, expected_url, status_code=302, target_status_code=200, host=None, msg_prefix='') assert_contains(response, text, count=None, status_code=200, msg_prefix='') assert_not_contains(response, text, count=None, status_code=200, msg_prefix='') assert_form_error(response, form, field, errors, msg_prefix='') assert_template_used(response, template_name, msg_prefix='') assert_template_not_used(response, template_name, msg_prefix='') assert_queryset_equal(qs, values, transform=repr) assert_num_queries(num, func=None, *args, **kwargs) assert_code(response, status_code, msg_prefix='') assert_ok(response, msg_prefix='') assert_mail_count(count, msg=None) Using With South ---------------- `South`_ installs its own test command that turns off migrations during testing. Make sure that django-nose comes *after* ``south`` in ``INSTALLED_APPS`` so that django_nose's test command is used. .. _South: http://south.aeracode.org/ Always Passing The Same Options ------------------------------- To always set the same command line options you can use a `nose.cfg or setup.cfg`_ (as usual) or you can specify them in settings.py like this:: NOSE_ARGS = ['--failed', '--stop'] .. _nose.cfg or setup.cfg: http://somethingaboutorange.com/mrl/projects/nose/0.11.2/usage.html#configuration Custom Plugins -------------- If you need to `make custom plugins`_, you can define each plugin class somewhere within your app and load them from settings.py like this:: NOSE_PLUGINS = [ 'yourapp.tests.plugins.SystematicDysfunctioner', # ... ] Just like middleware or anything else, each string must be a dot-separated, importable path to an actual class. Each plugin class will be instantiated and added to the Nose test runner. .. _make custom plugins: http://somethingaboutorange.com/mrl/projects/nose/0.11.2/plugins.html#writing-plugins Older Versions of Django ------------------------ Upgrading from Django <= 1.3 to Django 1.4 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ In versions of Django < 1.4 the project folder was in fact a python package as well (note the __init__.py in your project root). In Django 1.4, there is no such file and thus the project is not a python module. **When you upgrade your Django project to the Django 1.4 layout, you need to remove the __init__.py file in the root of your project (and move any python files that reside there other than the manage.py) otherwise you will get a `ImportError: No module named urls` exception.** This happens because Nose will intelligently try to populate your sys.path, and in this particular case includes your parent directory if your project has a __init__.py file (see: https://github.com/nose-devs/nose/blob/release_1.1.2/nose/importer.py#L134). This means that even though you have set up your directory structure properly and set your `ROOT_URLCONF='my_project.urls'` to match the new structure, when running django-nose's test runner it will try to find your urls.py file in `'my_project.my_project.urls'`. Upgrading from Django < 1.2 ~~~~~~~~~~~~~~~~~~~~~~~~~~~ Django 1.2 switches to a `class-based test runner`_. To use django-nose with Django 1.2, change your ``TEST_RUNNER`` from ``django_nose.run_tests`` to ``django_nose.NoseTestSuiteRunner``. ``django_nose.run_tests`` will continue to work in Django 1.2 but will raise a warning. In Django 1.3, it will stop working. If you were using ``django_nose.run_gis_tests``, you should also switch to ``django_nose.NoseTestSuiteRunner`` and use one of the `spatial backends`_ in your ``DATABASES`` settings. .. _class-based test runner: http://docs.djangoproject.com/en/dev/releases/1.2/#function-based-test-runners .. _spatial backends: http://docs.djangoproject.com/en/dev/ref/contrib/gis/db-api/#id1 Django 1.1 ~~~~~~~~~~ If you want to use django-nose with Django 1.1, use https://github.com/jbalogh/django-nose/tree/django-1.1 or http://pypi.python.org/pypi/django-nose/0.0.3. Django 1.0 ~~~~~~~~~~ django-nose does not support Django 1.0. Recent Version History ---------------------- 1.1 (2012-05-19) * Django TransactionTestCases don't clean up after themselves; they leave junk in the DB and clean it up only on ``_pre_setup``. Thus, Django makes sure these tests run last. Now django-nose does, too. This means one fewer source of failures on existing projects. (Erik Rose) * Add support for hygienic TransactionTestCases. (Erik Rose) * Support models that are used only for tests. Just put them in any file imported in the course of loading tests. No more crazy hacks necessary. (Erik Rose) * Make the fixture bundler more conservative, fixing some conceivable situations in which fixtures would not appear as intended if a TransactionTestCase found its way into the middle of a bundle. (Erik Rose) * Fix an error that would surface when using SQLAlchemy with connection pooling. (Roger Hu) * Gracefully ignore the new ``--liveserver`` option introduced in Django 1.4; don't let it through to nose. (Adam DePue) 1.0 (2012-03-12) * New fixture-bundling plugin for avoiding needless fixture setup (Erik Rose) * Moved FastFixtureTestCase in from test-utils, so now all the fixture-bundling stuff is in one library. (Erik Rose) * Added the REUSE_DB setting for faster startup and shutdown. (Erik Rose) * Fixed a crash when printing options with certain verbosities. (Daniel Abel) * Broke hard dependency on MySQL. Support PostgreSQL. (Roger Hu) * Support SQLite, both memory- and disk-based. (Roger Hu and Erik Rose) * Nail down versions of the package requirements. (Daniel Mizyrycki) 0.1.3 (2010-04-15) * Even better coverage support (rozza) * README fixes (carljm and ionelmc) * optparse OptionGroups are handled better (outofculture) * nose plugins are loaded before listing options See more in changelog.txt. django-nose-1.2/runtests.sh0000755000076500000240000000204512173535770016552 0ustar jbaloghstaff00000000000000#!/bin/sh export PYTHONPATH=. django_test() { TEST="$1" $TEST 2>&1 | grep "Ran $2 test" > /dev/null if [ $? -gt 0 ] then echo FAIL: $3 $TEST exit 1; else echo PASS: $3 fi # Check that we're hijacking the help correctly. $TEST --help 2>&1 | grep 'NOSE_DETAILED_ERRORS' > /dev/null if [ $? -gt 0 ] then echo FAIL: $3 '(--help)' exit 1; else echo PASS: $3 '(--help)' fi } django_test 'django-admin.py test --settings=testapp.settings' '2' 'normal settings' django_test 'django-admin.py test --settings=testapp.settings_with_south' '2' 'with south in installed apps' django_test 'django-admin.py test --settings=testapp.settings_old_style' '2' 'django_nose.run_tests format' django_test 'testapp/runtests.py testapp.test_only_this' '1' 'via run_tests API' django_test 'django-admin.py test --settings=testapp.settings_with_plugins testapp/plugin_t' '1' 'with plugins' django_test 'django-admin.py test --settings=testapp.settings unittests' '4' 'unittests' django-nose-1.2/setup.cfg0000644000076500000240000000007312173536173016142 0ustar jbaloghstaff00000000000000[egg_info] tag_build = tag_date = 0 tag_svn_revision = 0 django-nose-1.2/setup.py0000644000076500000240000000345612173536032016035 0ustar jbaloghstaff00000000000000import os from setuptools import setup, find_packages ROOT = os.path.abspath(os.path.dirname(__file__)) setup( name='django-nose', version='1.2', description='Makes your Django tests simple and snappy', long_description=open(os.path.join(ROOT, 'README.rst')).read(), author='Jeff Balogh', author_email='me@jeffbalogh.org', maintainer='Erik Rose', maintainer_email='erikrose@grinchcentral.com', url='http://github.com/jbalogh/django-nose', license='BSD', packages=find_packages(exclude=['testapp', 'testapp/*']), include_package_data=True, zip_safe=False, install_requires=['nose>=1.2.1', 'Django>=1.2'], tests_require=['south>=0.7'], # This blows up tox runs that install django-nose into a virtualenv, # because it causes Nose to import django_nose.runner before the Django # settings are initialized, leading to a mess of errors. There's no reason # we need FixtureBundlingPlugin declared as an entrypoint anyway, since you # need to be using django-nose to find the it useful, and django-nose knows # about it intrinsically. #entry_points=""" # [nose.plugins.0.10] # fixture_bundler = django_nose.fixture_bundling:FixtureBundlingPlugin # """, classifiers=[ 'Development Status :: 5 - Production/Stable', 'Environment :: Web Environment', 'Framework :: Django', 'Intended Audience :: Developers', 'License :: OSI Approved :: BSD License', 'Operating System :: OS Independent', 'Programming Language :: Python', 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3.3', 'Topic :: Software Development :: Testing' ] ) django-nose-1.2/testapp/0000755000076500000240000000000012173536173016001 5ustar jbaloghstaff00000000000000django-nose-1.2/testapp/__init__.py0000644000076500000240000000000012124726631020074 0ustar jbaloghstaff00000000000000django-nose-1.2/testapp/plugin_t/0000755000076500000240000000000012173536173017622 5ustar jbaloghstaff00000000000000django-nose-1.2/testapp/plugin_t/test_with_plugins.py0000644000076500000240000000016112124726631023741 0ustar jbaloghstaff00000000000000from nose.tools import eq_ def test_one(): from testapp import plugins eq_(plugins.plugin_began, True) django-nose-1.2/testapp/plugins.py0000644000076500000240000000052412124726631020031 0ustar jbaloghstaff00000000000000from nose.plugins import Plugin plugin_began = False class SanityCheckPlugin(Plugin): enabled = True def options(self, parser, env): """Register commandline options.""" def configure(self, options, conf): """Configure plugin.""" def begin(self): global plugin_began plugin_began = True django-nose-1.2/testapp/runtests.py0000755000076500000240000000101512124726631020236 0ustar jbaloghstaff00000000000000#!/usr/bin/env python import sys from django.conf import settings if not settings.configured: settings.configure( DATABASES={'default': {'ENGINE': 'django.db.backends.sqlite3'}}, INSTALLED_APPS=[ 'django_nose', ], ) from django_nose import NoseTestSuiteRunner def runtests(*test_labels): runner = NoseTestSuiteRunner(verbosity=1, interactive=True) failures = runner.run_tests(test_labels) sys.exit(failures) if __name__ == '__main__': runtests(*sys.argv[1:]) django-nose-1.2/testapp/settings.py0000644000076500000240000000035212173535770020215 0ustar jbaloghstaff00000000000000DATABASES = { 'default': { 'NAME': 'django_master', 'ENGINE': 'django.db.backends.sqlite3', } } INSTALLED_APPS = ( 'django_nose', ) TEST_RUNNER = 'django_nose.NoseTestSuiteRunner' SECRET_KEY = 'ssshhhh' django-nose-1.2/testapp/settings_old_style.py0000644000076500000240000000042012173535770022267 0ustar jbaloghstaff00000000000000DATABASES = { 'default': { 'NAME': 'django_master', 'ENGINE': 'django.db.backends.sqlite3', } } INSTALLED_APPS = ( 'django_nose', ) TEST_RUNNER = 'django_nose.NoseTestSuiteRunner' TEST_RUNNER = 'django_nose.run_tests' SECRET_KEY = 'sssshhh' django-nose-1.2/testapp/settings_with_plugins.py0000644000076500000240000000012512173535770023007 0ustar jbaloghstaff00000000000000from .settings import * NOSE_PLUGINS = [ 'testapp.plugins.SanityCheckPlugin' ] django-nose-1.2/testapp/settings_with_south.py0000644000076500000240000000010712173535770022470 0ustar jbaloghstaff00000000000000from .settings import * INSTALLED_APPS = ('south',) + INSTALLED_APPS django-nose-1.2/testapp/test_for_nose.py0000644000076500000240000000015012124726631021214 0ustar jbaloghstaff00000000000000"""Django's test runner won't find this, but nose will.""" def test_addition(): assert 1 + 1 == 2 django-nose-1.2/testapp/test_only_this.py0000644000076500000240000000015612124726631021420 0ustar jbaloghstaff00000000000000"""Django's test runner won't find this, but nose will.""" def test_multiplication(): assert 2 * 2 == 4