Nose is, in its own words, a 'discovery-based unittest extension'. Basically, it's a system that finds all of your unittests, runs them, and reports on the results. If you're looking to run unittests on your Python application, this is the place to go.
Sometimes you might want to run these tests under different conditions. For example, at Siafoo we sometimes run and debug the tests by hand, but usually they are run by our automated testing system on each SVN commit. We want the test database to be repopulated each time the automatic tests run, but this takes too long and is often unnecessary when we're running individual tests by hand.
To create a nose plugin, you need two things:
This article assumes you already have some sort of project that uses a 'setup.py' file. Explaining how to set that sort of thing up is really more effort than I'm willing to put in :-)
Also, I'm not trying to create an exhaustive tutorial with every possible option, but rather a simple how-to. Feel free to add any additional information that you think should be in here.
A nose plugin is a class that subclasses nose.plugins.Plugin. It should look something like this:
1# Written by David Isaacson
2# Copyright 2008 Siafoo.net
3# BSD License
6from nose.plugins import Plugin
9 name = 'my_app'
10 enabled = False
12 def add_options(self, parser, env=os.environ):
13 '''Add command-line options for plugin'''
14 env_opt = 'NOSE_PASTE_SETUP_FIRST'
20 help='Run setup-app in Paste before running tests. [%s]' % env_opt)
22 def configure(self, options, conf):
23 """Configure the plugin"""
24 Plugin.configure(self, options, conf)
25 if options.paste_setup:
26 self.enabled = True
28 def begin(self):
29 '''Called before any tests are collected or run. Resets database.'''
30 from paste.script.appinstall import SetupCommand
32 # Select the .ini file to run setup-app on
33 test_file = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), 'test.ini')
This example only defines one option, but multiple related options could (and should) be defined using the same class. Below, the properties and methods used in this example are explained more thoroughly.
There are two properties your class needs:
- name: A unique name for this plugin
- enabled: True or False, if the default behavior is on or off. If enabled is False, the begin method will not be run. Can be modified during execution to turn this method on and off.
This method is is responsible for -- you guessed it -- adding the options to nosetests. It should take two arguments (besides self): parser, the actual nose parser, and env, a dictionary to look for environment variables in.
All you really need to do in this method is call parser.add_option for each option you'd like to add. Use the syntax below.
parser.add_option(option_name, action = action, default = default, dest = dest, help = help)
|option_name||The actual option text to be used, like '--my-option'|
|action||What to do with the data provided on the command line. 'store_true' indicates the existence of the command-line option by storing True or False in dest. 'store' actually puts the value passed with the command line option into dest.|
|default||What to do if no option is provided. Typically, an environment variable starting with 'NOSE' is checked.|
|dest||Where to save the provided data. This variable is created in 'options', which is accessible to the configure method.|
|help||Help text to display when nosetests --help is run. Typically ends with the environment variable, in square brackets. Try running nosetests --help for some examples.|
This method is responsible for reading through the options dictionary that nose has created from the command-line options, and enabling or disabling your plugin based on these options. It should take two variables, the first of which is the options dictionary.
Don't forget to call the parent method, Plugin.configure at the top.
In the above example, I check to see if the relevant option is True, and if so set enabled to True.
This method actually does whatever it is your plugin does. It is only called if enabled is True.
Put your application-specific code here. In the example above I find a .ini file and pass it to Paste's setup-app command.
To install your plugin, you need to add a few lines to your setup.py file. In the entry_points string, add:
2my_app = siafoo.tests.plugin:MyPlugin
Now run python setup.py install (or whatever command you use to run setup.py).
Your option(s) should now show up under nosetests --help and should do something when you pass the option to nosetests.