Purpose: speeding up development with nose tests
Jump to section: nose step-by-step tutorial
This document describes how to setup your local development environment to run unit and/or integration tests in your Django project using nose, nose-exclude, and django-nose.
Why not just use Django’s test runner?
Recently, I worked on a heavily tested Django project. Running all tests in the project took several minutes, and the dependencies that were marked external in our Subversion project repository ran all of their tests too–each time project tests were run! I work on a team where testing frequently and committing often are tantamount to productivity. Nose tests can improve both testing speed, and subsequently accelerate development. As we walk through this tutorial you’ll begin to see how nose and its plugins (nose-exclude, django-nose) improve the productivity on any size Django project.
What nose and its plugins buy you?
- Exclude dependencies, directories, externals, or files you don’t need to test in your application.
- Run all tests that failed in the previous run.
- Identify slow-running tests.
- Get detailed information about tests that fail or error.
- Faster test runs.
- And so much more. Once you’ve completed this tutorial, open a terminal and type: nosetests –help.
What you’ll need to set up nose for Django
Although information in this tutorial can be used in almost any development environment, the walk-through for setting up nose and the related plug-ins was created and tested (of course) using the following:
- Ubuntu 9.10 (Karmic Koala)
- Python 2.64
- Django 1.1.1
- pip for installing nose, nose-exclude, and django-nose.
Nose gotchas, tips, and other “fun”
- It seems that Synaptic Package Manager installs the older package pip-0.3.1. Don’t use it. Remove it. Do this first: Go to: System > Administration > Synaptic Package Manager > search for pip > right-click on python-pip > Mark for removal > click Apply button etc.
- Don’t use TransactionTestCase; nose wraps every test in a transaction (batteries included)
Don’t use the word “test”, or any variation thereof, in any method or class name; however, you can “exclude” certain non-tests from nose in the setup.cfg file discussed later in this tutorial.
Thanks to Jon Sackett for his comment on using the decorator @nottest on methods that have “test” in the name.
Tutorial: Setting up and installing nose, nose-exclude, and django-nose
- Open a terminal, and pip uninstall or remove any previous versions of django-nose, nose, nose-exclude.
Note: This step may require finding and deleting older versions of pip installed on Ubuntu; ie. pip-0.3.1 (type pip –version to see which you have) -
Next, install pip-0.6.3 if you haven’t already. Download the source tarball (pip-0.6.3.tar.gz), extract it, and cd into the extraction directory.
- In the terminal type: sudo python setup.py install
- type: pip –version (if you don’t see 0.6.3, make sure you’ve removed all pip eggs and directories system-wide, and try again.)
- terminal: pip install nose –upgrade
- terminal: pip install django-nose –upgrade
- IMPORTANT: cd out of the current project you’re working in (some projects will have ‘nose-exclude’ as part of the build directory); I cd into my home directory, and then type: pip install nose-exclude.
- Now go back to your project directory, and create a new file named nose_exclude.txt. See Using File-Based Exclusion List for what should go in this file. My recommendation is to create a file named nose_exclude.txt.tmpl with some common settings to keep track of the application dependencies or directories that you don’t want or need to test.
- Likewise, create a new file in you project’s root directory named setup.cfg. This file contains the options or flags that you want to pass to “python manage.py test” every time you run tests. Optionally create one or more template files with predefined settings much like the nose_exclude.txt.tmpl file recommended above. This will help with different testing scenarios. For example, you probably don’t want to run coverage every time you execute all of your tests, but you might create a template that caters specifically to coverage or any other options not normally executed in your test runs.
- See django-nose for changes you’ll need to make to settings.py in order to run tests using nose. Depending on your development environment, you may prefer to place these edits in a different file that gets pulled into settings.py.
Finally, cd into your Django project, and type python manage.py test as you normally would. Now you have nose!
Command differences between django-nose and the Django test runner
Classes that inherit from Django’s TestCase class and their test methods require special syntax. See below for examples.
python manage.py test app.tests:YourTestCaseClass
One quick note on your gotchas:
You can actually use test in things, you just have to decorate those methods/classes with @nottest, which is a pretty handy decorator.
Cool! Nice to know. Thanks for the info!
Thanks for the info – got me up and running quickly!
Of course! I’m glad I could be of help 🙂
Thanks for the post!
Why is it important to install nose-exclude from outside the project? My understanding is
that pip installs packages system wide (or vm-wide if in a virtualenv). It should not matter where you invoke that command.
Also, how do you get nose to actually read the nose_exclude.txt file? Surely you have to tell
it the name of that somewhere. An example of the settings.py file and setup.cfg would be really
helpful.
Hi Adrian,
You’re absolutely correct: installation outside of your project directory not 100% necessary. pip can handle installation fine as long as you don’t have external projects being put in a sub directory of your project.
I don’t have a sample setup.py at hand, but here’s sample setup.cfg contents:
[nosetests]
nocapture=1
nologcapture=0
no-deprecated=1
detailed-errors=1
failure-detail=1
######
# The following are necessary, and require nose-exclude
# $ pip install nose-exclude
# REQUIRED for nose-exclude
exclude=^custom_tests()$
with-noseexclude=1
exclude-dir-file=nose_exclude.txt
As for the nose_exclude.txt just list each directory you want to exclude from testing in the project–one per line, like so:
an_app_inside_your_project_directory/and_some_sub_directory
Thanks for the questions! Let me know if you have any others 🙂
Hey, nice post. you say thaty nose can “Identify slow-running tests” – how do you do that? I tried playing around with the profiling plugin, but the output is way to verbose and I don’t want to really profile code (yet). I just want a list of all my tests along with the time it took to run each test…
Thanks for the comment.
As for timing your tests, try pinnochio and the –with-stopwatch option 🙂
http://darcs.idyll.org/~t/projects/pinocchio/doc/