1
testresources: extensions to python unittest to allow declaritive use
1
testresources: extensions to python unittest to allow declarative use
2
2
of resources by test cases.
4
Copyright (C) 2005-2008 Robert Collins <robertc@robertcollins.net>
6
This program is free software; you can redistribute it and/or modify
7
it under the terms of the GNU General Public License as published by
8
the Free Software Foundation; either version 2 of the License, or
9
(at your option) any later version.
11
This program is distributed in the hope that it will be useful,
12
but WITHOUT ANY WARRANTY; without even the implied warranty of
13
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
GNU General Public License for more details.
16
You should have received a copy of the GNU General Public License
17
along with this program; if not, write to the Free Software
18
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
4
Copyright (C) 2005-2010 Robert Collins <robertc@robertcollins.net>
6
Licensed under either the Apache License, Version 2.0 or the BSD 3-clause
7
license at the users choice. A copy of both licenses are available in the
8
project source as Apache-2.0 and BSD. You may not use this file except in
9
compliance with one of these two licences.
11
Unless required by applicable law or agreed to in writing, software
12
distributed under these licenses is distributed on an "AS IS" BASIS, WITHOUT
13
WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14
license you chose for the specific language governing permissions and
15
limitations under that license.
17
See the COPYING file for full details on the licensing of Testresources.
21
23
testresources is attempting to extend unittest with a clean and simple api to
22
24
provide test optimisation where expensive common resources are needed for test
23
25
cases - for example sample working trees for VCS systems, reference databases
24
26
for enterprise applications, or web servers ... let imagination run wild.
33
35
can use testresources in your own app without using testtools.
36
How testresources works:
37
========================
39
These are the main components to make testresources work:
41
1) testresources.TestResource
43
A TestResource is an object that tests can use. Usually a subclass of
44
testresources.TestResource, with the make and possibly the clean and isDirty
45
methods overridden. These methods create, decide on reuse and free resources.
47
The 'resources' list on the TestResource object is used to declare
38
How testresources Works
39
=======================
41
The basic idea of testresources is:
43
* Tests declare the resources they need in a ``resources`` attribute.
44
* When the test is run, the required resource objects are allocated (either
45
newly constructed, or reused), and assigned to attributes of the TestCase.
47
testresources distinguishes a 'resource manager' (a subclass of
48
``TestResourceManager``) which acts as a kind of factory, and a 'resource'
49
which can be any kind of object returned from the manager class's
50
``getResource`` method.
52
Resources are either clean or dirty. Being clean means they have same state in
53
all important ways as a newly constructed instance and they can therefore be
59
testresources.ResourcedTestCase
60
-------------------------------
62
By extending or mixing-in this class, tests can have necessary resources
63
automatically allocated and disposed or recycled.
65
ResourceTestCase can be used as a base class for tests, and when that is done
66
tests will have their ``resources`` attribute automatically checked for
67
resources by both OptimisingTestSuite and their own setUp() and tearDown()
68
methods. (This allows tests to remain functional without needing this specific
69
TestSuite as a container). Alternatively, you can call setUpResources(self,
70
resources, test_result) and tearDownResources(self, resources, test_result)
71
from your own classes setUp and tearDown and the same behaviour will be
74
To declare the use of a resource, set the ``resources`` attribute to a list of
75
tuples of ``(attribute_name, resource_factory)``.
77
During setUp, for each declared requirement, the test gains an attribute
78
pointing to an allocated resource, which is the result of calling
79
``resource_factory.getResource()``. ``finishedWith`` will be called on each
80
resource during tearDown().
84
class TestLog(testresources.TestCase):
86
resources = [('branch', BzrPopulatedBranch())]
89
show_log(self.branch, ...)
91
testresources.TestResourceManager
92
---------------------------------
94
A TestResourceManager is an object that tests can use to create resources. It
95
can be overridden to manage different types of resources. Normally test code
96
doesn't need to call any methods on it, as this will be arranged by the
97
testresources machinery.
99
When implementing a new ``TestResourceManager`` subclass you should consider
100
overriding these methods:
103
Must be overridden in every concrete subclass.
105
Returns a new instance of the resource object
106
(the actual resource, not the TestResourceManager). Doesn't need to worry about
107
reuse, which is taken care of separately. This method is only called when a
108
new resource is definitely needed.
111
Cleans up an existing resource instance, eg by deleting a directory or
112
closing a network connection. By default this does nothing, which may be
113
appropriate for resources that are automatically garbage collected.
116
Reset a no-longer-used dirty resource to a clean state. By default this
117
just discards it and creates a new one, but for some resources there may be a
118
faster way to reset them.
121
Check whether an existing resource is dirty. By default this just reports whether
122
``TestResourceManager.dirtied`` has been called.
126
class TemporaryDirectoryResource(TestResourceManager):
128
def clean(self, resource):
129
osutils.rmtree(resource)
132
return tempfile.mkdtemp()
134
def isDirty(self, resource):
135
# Can't detect when the directory is written to, so assume it
136
# can never be reused. We could list the directory, but that might
137
# not catch it being open as a cwd etc.
140
The ``resources`` list on the TestResourceManager object is used to declare
48
141
dependencies. For instance, a DataBaseResource that needs a TemporaryDirectory
49
142
might be declared with a resources list::
51
class DataBaseResource(TestResource):
144
class DataBaseResource(TestResourceManager):
53
146
resources = [("scratchdir", TemporaryDirectoryResource())]
55
Most importantly, two getResources to the same TestResource with no
56
finishedWith call in the middle, will return the same object as long as it has
57
not been marked dirty.
148
Most importantly, two getResources to the same TestResourceManager with no
149
finishedWith call in the middle, will return the same object as long as it is
59
152
When a Test has a dependency and that dependency successfully completes but
60
153
returns None, the framework does *not* consider this an error: be sure to always
61
154
return a valid resource, or raise an error. Error handling hasn't been heavily
62
155
exercised, but any bugs in this area will be promptly dealt with.
64
A sample TestResource can be found in the doc/ folder.
66
See pydoc testresources.TestResource for details.
69
2) testresources.OptimisingTestSuite
157
A sample TestResourceManager can be found in the doc/ folder.
159
See pydoc testresources.TestResourceManager for details.
161
testresources.GenericResource
162
-----------------------------
164
Glue to adapt testresources to an existing resource-like class.
166
testresources.OptimisingTestSuite
167
---------------------------------
71
169
This TestSuite will introspect all the test cases it holds directly and if
72
170
they declare needed resources, will run the tests in an order that attempts to
87
185
OptimisingTestSuites.
90
3) testresources.ResourcedTestCase
92
ResourceTestCase can be used as a base class for tests, and when that is done
93
tests will have their resources attribute automatically checked for resources
94
by both OptimisingTestSuite and their own setUp() and tearDown() methods.
95
(This allows tests to remain functional without needing this specific
96
TestSuite as a container). Alternatively, you can call
97
ResourceTestCase.setUpResources(self) and
98
ResourceTestCase.tearDownResources(self) from your own classes setUp and
99
tearDown and the same behaviour will be activated.
101
To declare the use of a resource, set resources as an attribute listing tuples
102
of (attribute name, TestResource). During setUp, self._attribute_name will be
103
set to TestResource.getResource(), and finishedWith() will be called for you
107
4) testresources.TestLoader
188
testresources.TestLoader
189
------------------------
109
191
This is a trivial TestLoader that creates OptimisingTestSuites by default.
111
5) unittest.TestResult
113
196
testresources will log activity about resource creation and destruction to the
114
197
result object tests are run with. 4 extension methods are looked for:
115
198
``startCleanResource``, ``stopCleanResource``, ``startMakeResource``,
116
199
``stopMakeResource``. ``testresources.tests.ResultWithResourceExtensions`` is
117
200
an example of a ``TestResult`` with these methods present.
202
Controlling Resource Reuse
203
==========================
205
When or how do I mark the resource dirtied?
207
The simplest approach is to have ``TestResourceManager.make`` call ``self.dirtied``:
208
the resource is always immediately dirty and will never be reused without first
209
being reset. This is appropriate when the underlying resource is cheap to
210
reset or recreate, or when it's hard to detect whether it's been dirtied or to
211
trap operations that change it.
213
Alternatively, override ``TestResourceManager.isDirty`` and inspect the resource to
214
see if it is safe to reuse.
216
Finally, you can arrange for the returned resource to always call back to
217
``TestResourceManager.dirtied`` on the first operation that mutates it.
222
* Can I dynamically request resources inside a test method?
224
Generally, no, you shouldn't do this. The idea is that the resources are
225
declared statically, so that testresources can "smooth" resource usage across
228
* If the resource is held inside the TestResourceManager object, and the
229
TestResourceManager is typically constructed inline in the test case
230
``resources`` attribute, how can they be shared across different test
235
I guess you should arrange for a single instance to be held in an appropriate
236
module scope, then referenced by the test classes that want to share it.