ErrorClass plugins provide an easy way to add support for custom handling of particular classes of exceptions.
An ErrorClass plugin defines one or more ErrorClasses and how each is handled and reported on. Each error class is stored in a different attribute on the result, and reported separately. Each error class must indicate the exceptions that fall under that class, the label to use for reporting, and whether exceptions of the class should be considered as failures for the whole test run.
ErrorClasses use a declarative syntax. Assign an ErrorClass to the attribute you wish to add to the result object, defining the exceptions, label and isfailure attributes. For example, to declare an ErrorClassPlugin that defines TodoErrors (and subclasses of TodoError) as an error class with the label ‘TODO’ that is considered a failure, do this:
>>> class Todo(Exception): ... pass >>> class TodoError(ErrorClassPlugin): ... todo = ErrorClass(Todo, label='TODO', isfailure=True)
The MetaErrorClass metaclass translates the ErrorClass declarations into the tuples used by the error handling and reporting functions in the result. This is an internal format and subject to change; you should always use the declarative syntax for attaching ErrorClasses to an ErrorClass plugin.
>>> TodoError.errorClasses ((<class ...Todo...>, ('todo', 'TODO', True)),)
Let’s see the plugin in action. First some boilerplate.
>>> import sys >>> import unittest >>> try: ... # 2.7+ ... from unittest.runner import _WritelnDecorator ... except ImportError: ... from unittest import _WritelnDecorator ... >>> buf = _WritelnDecorator(sys.stdout)
Now define a test case that raises a Todo.
>>> class TestTodo(unittest.TestCase): ... def runTest(self): ... raise Todo("I need to test something") >>> case = TestTodo()
Prepare the result using our plugin. Normally this happens during the course of test execution within nose – you won’t be doing this yourself. For the purposes of this testing document, I’m stepping through the internal process of nose so you can see what happens at each step.
>>> plugin = TodoError() >>> from nose.result import _TextTestResult >>> result = _TextTestResult(stream=buf, descriptions=0, verbosity=2) >>> plugin.prepareTestResult(result)
Now run the test. TODO is printed.
>>> _ = case(result) runTest (....TestTodo) ... TODO: I need to test something
Errors and failures are empty, but todo has our test:
>>> result.errors  >>> result.failures  >>> result.todo [(<....TestTodo testMethod=runTest>, '...Todo: I need to test something\n')] >>> result.printErrors() ====================================================================== TODO: runTest (....TestTodo) ---------------------------------------------------------------------- Traceback (most recent call last): ... ...Todo: I need to test something Traceback (most recent call last): ... ...Todo: I need to test something
Since we defined a Todo as a failure, the run was not successful.
>>> result.wasSuccessful() False