summaryrefslogtreecommitdiff
path: root/functional_tests/doc_tests/test_init_plugin/init_plugin.rst
blob: 6c640297215023a602e007db6f33bd8fae0a467a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
Running Initialization Code Before the Test Run
-----------------------------------------------

Many applications, especially those using web frameworks like Pylons_
or Django_, can't be tested without first being configured or
otherwise initialized. Plugins can fulfill this requirement by
implementing :meth:`begin() <nose.plugins.base.IPluginInterface.begin>`.

In this example, we'll use a very simple example: a widget class that
can't be tested without a configuration.

Here's the widget class. It's configured at the class or instance
level by setting the ``cfg`` attribute to a dictionary.

    >>> class ConfigurableWidget(object):
    ...     cfg = None
    ...     def can_frobnicate(self):
    ...         return self.cfg.get('can_frobnicate', True)
    ...     def likes_cheese(self):
    ...         return self.cfg.get('likes_cheese', True)

The tests verify that the widget's methods can be called without
raising any exceptions.

    >>> import unittest
    >>> class TestConfigurableWidget(unittest.TestCase):
    ...     longMessage = False
    ...     def setUp(self):
    ...         self.widget = ConfigurableWidget()
    ...     def test_can_frobnicate(self):
    ...         """Widgets can frobnicate (or not)"""
    ...         self.widget.can_frobnicate()
    ...     def test_likes_cheese(self):
    ...         """Widgets might like cheese"""
    ...         self.widget.likes_cheese()
    ...     def shortDescription(self): # 2.7 compat
    ...         try:
    ...             doc = self._testMethodDoc
    ...         except AttributeError:
    ...             # 2.4 compat
    ...             doc = self._TestCase__testMethodDoc
    ...         return doc and doc.split("\n")[0].strip() or None

The tests are bundled into a suite that we can pass to the test runner.

    >>> def suite():
    ...     return unittest.TestSuite([
    ...         TestConfigurableWidget('test_can_frobnicate'),
    ...         TestConfigurableWidget('test_likes_cheese')])

When we run tests without first configuring the ConfigurableWidget,
the tests fail.

.. Note ::

   The function :func:`nose.plugins.plugintest.run` reformats test result
   output to remove timings, which will vary from run to run, and
   redirects the output to stdout.

    >>> from nose.plugins.plugintest import run_buffered as run

..

    >>> argv = [__file__, '-v']
    >>> run(argv=argv, suite=suite())  # doctest: +REPORT_NDIFF
    Widgets can frobnicate (or not) ... ERROR
    Widgets might like cheese ... ERROR
    <BLANKLINE>
    ======================================================================
    ERROR: Widgets can frobnicate (or not)
    ----------------------------------------------------------------------
    Traceback (most recent call last):
    ...
    AttributeError: 'NoneType' object has no attribute 'get'
    <BLANKLINE>
    ======================================================================
    ERROR: Widgets might like cheese
    ----------------------------------------------------------------------
    Traceback (most recent call last):
    ...
    AttributeError: 'NoneType' object has no attribute 'get'
    <BLANKLINE>
    ----------------------------------------------------------------------
    Ran 2 tests in ...s
    <BLANKLINE>
    FAILED (errors=2)

To configure the widget system before running tests, write a plugin
that implements :meth:`begin() <nose.plugins.base.IPluginInterface.begin>`
and initializes the system with a hard-coded configuration. (Later, we'll
write a better plugin that accepts a command-line argument specifying the
configuration file.)

    >>> from nose.plugins import Plugin
    >>> class ConfiguringPlugin(Plugin):
    ...     enabled = True
    ...     def configure(self, options, conf):
    ...         pass # always on
    ...     def begin(self):
    ...         ConfigurableWidget.cfg = {}

Now configure and execute a new test run using the plugin, which will
inject the hard-coded configuration.

    >>> run(argv=argv, suite=suite(),
    ...     plugins=[ConfiguringPlugin()])  # doctest: +REPORT_NDIFF
    Widgets can frobnicate (or not) ... ok
    Widgets might like cheese ... ok
    <BLANKLINE>
    ----------------------------------------------------------------------
    Ran 2 tests in ...s
    <BLANKLINE>
    OK

This time the tests pass, because the widget class is configured.

But the ConfiguringPlugin is pretty lame -- the configuration it
installs is hard coded. A better plugin would allow the user to
specify a configuration file on the command line:

    >>> class BetterConfiguringPlugin(Plugin):
    ...     def options(self, parser, env={}):
    ...         parser.add_option('--widget-config', action='store',
    ...                           dest='widget_config', default=None,
    ...                           help='Specify path to widget config file')
    ...     def configure(self, options, conf):
    ...         if options.widget_config:
    ...             self.load_config(options.widget_config)
    ...             self.enabled = True
    ...     def begin(self):
    ...         ConfigurableWidget.cfg = self.cfg
    ...     def load_config(self, path):
    ...         from ConfigParser import ConfigParser
    ...         p = ConfigParser()
    ...         p.read([path])
    ...         self.cfg = dict(p.items('DEFAULT'))

To use the plugin, we need a config file.

    >>> import os
    >>> cfg_file = os.path.join(os.path.dirname(__file__), 'example.cfg')
    >>> bytes = open(cfg_file, 'w').write("""\
    ... [DEFAULT]
    ... can_frobnicate = 1
    ... likes_cheese = 0
    ... """)

Now we can execute a test run using that configuration, after first
resetting the widget system to an unconfigured state.

    >>> ConfigurableWidget.cfg = None
    >>> argv = [__file__, '-v', '--widget-config', cfg_file]
    >>> run(argv=argv, suite=suite(),
    ...     plugins=[BetterConfiguringPlugin()]) # doctest: +REPORT_NDIFF
    Widgets can frobnicate (or not) ... ok
    Widgets might like cheese ... ok
    <BLANKLINE>
    ----------------------------------------------------------------------
    Ran 2 tests in ...s
    <BLANKLINE>
    OK

.. _Pylons: http://pylonshq.com/
.. _Django: http://www.djangoproject.com/