Imported Upstream version 1.1.2
[platform/upstream/python-nose.git] / functional_tests / doc_tests / test_init_plugin / init_plugin.rst
1 Running Initialization Code Before the Test Run
2 -----------------------------------------------
3
4 Many applications, especially those using web frameworks like Pylons_
5 or Django_, can't be tested without first being configured or
6 otherwise initialized. Plugins can fulfill this requirement by
7 implementing :meth:`begin() <nose.plugins.base.IPluginInterface.begin>`.
8
9 In this example, we'll use a very simple example: a widget class that
10 can't be tested without a configuration.
11
12 Here's the widget class. It's configured at the class or instance
13 level by setting the ``cfg`` attribute to a dictionary.
14
15     >>> class ConfigurableWidget(object):
16     ...     cfg = None
17     ...     def can_frobnicate(self):
18     ...         return self.cfg.get('can_frobnicate', True)
19     ...     def likes_cheese(self):
20     ...         return self.cfg.get('likes_cheese', True)
21
22 The tests verify that the widget's methods can be called without
23 raising any exceptions.
24
25     >>> import unittest
26     >>> class TestConfigurableWidget(unittest.TestCase):
27     ...     longMessage = False
28     ...     def setUp(self):
29     ...         self.widget = ConfigurableWidget()
30     ...     def test_can_frobnicate(self):
31     ...         """Widgets can frobnicate (or not)"""
32     ...         self.widget.can_frobnicate()
33     ...     def test_likes_cheese(self):
34     ...         """Widgets might like cheese"""
35     ...         self.widget.likes_cheese()
36     ...     def shortDescription(self): # 2.7 compat
37     ...         try:
38     ...             doc = self._testMethodDoc
39     ...         except AttributeError:
40     ...             # 2.4 compat
41     ...             doc = self._TestCase__testMethodDoc
42     ...         return doc and doc.split("\n")[0].strip() or None
43
44 The tests are bundled into a suite that we can pass to the test runner.
45
46     >>> def suite():
47     ...     return unittest.TestSuite([
48     ...         TestConfigurableWidget('test_can_frobnicate'),
49     ...         TestConfigurableWidget('test_likes_cheese')])
50
51 When we run tests without first configuring the ConfigurableWidget,
52 the tests fail.
53
54 .. Note ::
55
56    The function :func:`nose.plugins.plugintest.run` reformats test result
57    output to remove timings, which will vary from run to run, and
58    redirects the output to stdout.
59
60     >>> from nose.plugins.plugintest import run_buffered as run
61
62 ..
63
64     >>> argv = [__file__, '-v']
65     >>> run(argv=argv, suite=suite())  # doctest: +REPORT_NDIFF
66     Widgets can frobnicate (or not) ... ERROR
67     Widgets might like cheese ... ERROR
68     <BLANKLINE>
69     ======================================================================
70     ERROR: Widgets can frobnicate (or not)
71     ----------------------------------------------------------------------
72     Traceback (most recent call last):
73     ...
74     AttributeError: 'NoneType' object has no attribute 'get'
75     <BLANKLINE>
76     ======================================================================
77     ERROR: Widgets might like cheese
78     ----------------------------------------------------------------------
79     Traceback (most recent call last):
80     ...
81     AttributeError: 'NoneType' object has no attribute 'get'
82     <BLANKLINE>
83     ----------------------------------------------------------------------
84     Ran 2 tests in ...s
85     <BLANKLINE>
86     FAILED (errors=2)
87
88 To configure the widget system before running tests, write a plugin
89 that implements :meth:`begin() <nose.plugins.base.IPluginInterface.begin>`
90 and initializes the system with a hard-coded configuration. (Later, we'll
91 write a better plugin that accepts a command-line argument specifying the
92 configuration file.)
93
94     >>> from nose.plugins import Plugin
95     >>> class ConfiguringPlugin(Plugin):
96     ...     enabled = True
97     ...     def configure(self, options, conf):
98     ...         pass # always on
99     ...     def begin(self):
100     ...         ConfigurableWidget.cfg = {}
101
102 Now configure and execute a new test run using the plugin, which will
103 inject the hard-coded configuration.
104
105     >>> run(argv=argv, suite=suite(),
106     ...     plugins=[ConfiguringPlugin()])  # doctest: +REPORT_NDIFF
107     Widgets can frobnicate (or not) ... ok
108     Widgets might like cheese ... ok
109     <BLANKLINE>
110     ----------------------------------------------------------------------
111     Ran 2 tests in ...s
112     <BLANKLINE>
113     OK
114
115 This time the tests pass, because the widget class is configured.
116
117 But the ConfiguringPlugin is pretty lame -- the configuration it
118 installs is hard coded. A better plugin would allow the user to
119 specify a configuration file on the command line:
120
121     >>> class BetterConfiguringPlugin(Plugin):
122     ...     def options(self, parser, env={}):
123     ...         parser.add_option('--widget-config', action='store',
124     ...                           dest='widget_config', default=None,
125     ...                           help='Specify path to widget config file')
126     ...     def configure(self, options, conf):
127     ...         if options.widget_config:
128     ...             self.load_config(options.widget_config)
129     ...             self.enabled = True
130     ...     def begin(self):
131     ...         ConfigurableWidget.cfg = self.cfg
132     ...     def load_config(self, path):
133     ...         from ConfigParser import ConfigParser
134     ...         p = ConfigParser()
135     ...         p.read([path])
136     ...         self.cfg = dict(p.items('DEFAULT'))
137
138 To use the plugin, we need a config file.
139
140     >>> import os
141     >>> cfg_file = os.path.join(os.path.dirname(__file__), 'example.cfg')
142     >>> bytes = open(cfg_file, 'w').write("""\
143     ... [DEFAULT]
144     ... can_frobnicate = 1
145     ... likes_cheese = 0
146     ... """)
147
148 Now we can execute a test run using that configuration, after first
149 resetting the widget system to an unconfigured state.
150
151     >>> ConfigurableWidget.cfg = None
152     >>> argv = [__file__, '-v', '--widget-config', cfg_file]
153     >>> run(argv=argv, suite=suite(),
154     ...     plugins=[BetterConfiguringPlugin()]) # doctest: +REPORT_NDIFF
155     Widgets can frobnicate (or not) ... ok
156     Widgets might like cheese ... ok
157     <BLANKLINE>
158     ----------------------------------------------------------------------
159     Ran 2 tests in ...s
160     <BLANKLINE>
161     OK
162
163 .. _Pylons: http://pylonshq.com/
164 .. _Django: http://www.djangoproject.com/