5
nose2 supports plugins for test collection, selection, observation and
6
reporting -- among other things. There are two basic rules for plugins:
8
* Plugin classes must subclass :class:`nose2.events.Plugin`.
10
* Plugins may implement any of the methods described in the
11
:doc:`hook_reference`.
17
Here's a basic plugin. It doesn't do anything besides log a message at
18
the start of a test run.
20
.. code-block:: python
25
from nose2.events import Plugin
27
log = logging.getLogger('nose2.plugins.helloworld')
29
class HelloWorld(Plugin):
30
configSection = 'helloworld'
31
commandLineSwitch = (None, 'hello-world', 'Say hello!')
33
def startTestRun(self, event):
34
log.info('Hello pluginized world!')
36
To see this plugin in action, save it into an importable module, then
37
add that module to the ``plugins`` key in the ``[unittest]`` section
38
of a config file loaded by nose2, such as ``unittest.cfg``. Then run
41
nose2 --log-level=INFO --hello-world
43
And you should see the log message before the first dot appears.
49
As mentioned above, for nose2 to find a plugin, it must be in an
50
importable module, and the module must be listed under the ``plugins``
51
key in the ``[unittest]`` section of a config file loaded by nose2:
56
plugins = mypackage.someplugin
57
otherpackage.thatplugin
58
thirdpackage.plugins.metoo
60
As you can see, plugin *modules* are listed, one per line. All plugin
61
classes in those modules will be loaded -- but not necessarily
62
active. Typically plugins do not activate themselves ("register")
63
without seeing a command-line flag, or ``always-on = True`` in their
70
nose2 uses `argparse`_ for command-line argument parsing. Plugins may
71
enable command-line options that register them as active, or take
72
arguments or flags controlling their operation.
74
The most basic thing to do is to set the plugin's
75
``commandLineSwitch`` attribute, which will automatically add a
76
command-line flag that registers the plugin.
78
To add other flags or arguments, you can use the Plugin methods
79
:meth:`nose2.events.Plugin.addFlag`,
80
:meth:`nose2.events.Plugin.addArgument` or
81
:meth:`nose2.events.Plugin.addOption`. If those don't offer enough
82
flexibility, you can directly manipulate the argument parser by
83
accessing ``self.session.argparse`` or the plugin option group by
84
accessing ``self.session.pluginargs``.
86
Please note though that the *majority* of your plugin's configuration
87
should be done via config file options, not command line options.
93
Plugins may specify a config file section that holds their
94
configuration by setting their ``configSection`` attribute. All
95
plugins, regardless of whether they specify a config section, have a
96
``config`` attribute that holds a :class:`nose2.config.Config`
97
instance. This will be empty of values if the plugin does not specify
98
a config section or if no loaded config file includes that section.
100
Plugins should extract the user's configuration selections from their
101
config attribute in their ``__init__`` methods. Plugins that want to
102
use nose2's `Sphinx`_ extension to automatically document themselves
105
Config file options may be extracted as strings, ints, booleans or
108
You should provide reasonable defaults for all config options.
116
nose2's plugin api is based on the api in unittest2's
117
under-development plugins branch. It differs from nose's plugins api
118
in one major area: what it passes to hooks. Where nose passes a
119
variety of arguments, nose2 *always passes an event*. The events are
120
listed in the :doc:`event_reference`.
122
Here's the key thing about that: *event attributes are
123
read-write*. Unless stated otherwise in the documentation for a hook,
124
you can set a new value for any event attribute, and *this will do
125
something*. Plugins and nose2 systems will see that new value and
126
either use it instead of what was originally set in the event
127
(example: the reporting stream or test executor), or use it to
128
supplement something they find elsewhere (example: extraTests on a
134
Many hooks give plugins a chance to completely handle events,
135
bypassing other plugins and any core nose2 operations. To do this, a
136
plugin sets ``event.handled`` to True and, generally, returns an
137
appropriate value from the hook method. What is an appropriate value
138
varies by hook, and some hooks *can't* be handled in this way. But
139
even for hooks where handling the event doesn't stop all processing,
140
it *will* stop subsequently-loaded plugins from seeing the event.
145
nose2 uses the logging classes from the standard library. To enable users
146
to view debug messages easily, plugins should use ``logging.getLogger()`` to
147
acquire a logger in the ``nose2.plugins`` namespace.
156
* Writing a plugin that monitors or controls test result output
158
Implement any of the ``report*`` hook methods, especially if you
159
want to output to the console. If outputing to file or other system,
160
you might implement :func:`testOutcome` instead.
162
Example: :class:`nose2.plugins.result.ResultReporter`
164
* Writing a plugin that handles exceptions
166
If you just want to handle some exceptions as skips or failures
167
instead of errors, see :class:`nose2.plugins.outcomes.Outcomes`,
168
which offers a simple way to do that. Otherwise, implement
169
:func:`setTestOutcome` to change test outcomes.
171
Example: :class:`nose2.plugins.outcomes.Outcomes`
173
* Writing a plugin that adds detail to error reports
175
Implement :func:`testOutcome` and put your extra information into
176
``event.metadata``, then implement :func:`outcomeDetail` to extract
177
it and add it to the error report.
179
Examples: :class:`nose2.plugins.buffer.OutputBufferPlugin`, :class:`nose2.plugins.logcapture.LogCapture`
181
* Writing a plugin that loads tests from files other than python modules
183
Implement :func:`handleFile`.
185
Example: :class:`nose2.plugins.doctests.DocTestLoader`
187
* Writing a plugin that loads tests from python modules
189
Implement at least :func:`loadTestsFromModule`.
191
.. _loading-from-module:
195
One thing to beware of here is that if you return tests as
196
dynamically-generated test cases, or instances of a testcase
197
class that is defined *anywhere* but the module being loaded, you
198
*must* use :func:`nose2.util.transplant_class` to make the test
199
case class appear to have originated in that module. Otherwise,
200
module-level fixtures will not work for that test, and may be
201
ignored entirely for the module if there are no test cases that
202
are or appear to be defined there.
204
* Writing a plugin that prints a report
206
Implement :func:`beforeErrorList`, :func:`beforeSummaryReport` or
207
:func:`afterSummaryReport`
209
Example: :class:`nose2.plugins.prof.Profiler`
211
* Writing a plugin that selects or rejects tests
213
Implement :class:`matchPath` or :class:`getTestCaseNames`.
215
Example: :class:`nose2.plugins.loader.parameters.Parameters`
217
.. _argparse : http://pypi.python.org/pypi/argparse/1.2.1
218
.. _Sphinx : http://sphinx.pocoo.org/