Skip to content

EmployInsight/django-nose

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

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 running a specific test)
    • 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

  • Support for various databases. Tested with MySQL, PostgreSQL, and SQLite. Others should work as well.

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.

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.

Enabling Fast Fixtures

django-nose includes a nose plugin 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.)
  2. Activate the plugin by passing the --with-fixture-bundling option to ./manage.py test.

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.

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.

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']

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.

Older Versions of Django

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.

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.0.1
  • Fixed an error that would surface when using SQLAlchemy with connection pooling. (Roger Hu)
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.