paula.testing: WIP
[paula.git] / paula.app.testing / src / paula / app / testing / testing.py
blob201c5155b2f2373f1e0cd4b90fc53b6fa50d2a1d
1 # Copyright (c) 2008 by Florian Friesdorf
3 # GNU Affero General Public License (AGPL)
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU Affero General Public License as
7 # published by the Free Software Foundation; either version 3 of the
8 # License, or (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU Affero General Public License for more details.
15 # You should have received a copy of the GNU Affero General Public
16 # License along with this program. If not, see
17 # <http://www.gnu.org/licenses/>.
18 """
19 """
20 __author__ = "Florian Friesdorf <flo@chaoflow.net>"
21 __docformat__ = "plaintext"
23 import os
24 import os.path
25 import unittest
27 from zope.app.testing.functional import ZCMLLayer, FunctionalDocFileSuite
28 from zope.component import testing
30 from zope.testing import doctest
31 from zope.testing import doctestunit
33 # --- stuff for globs -------------------------------------------------
35 from UserDict import UserDict
36 from UserList import UserList
38 from zope.component import provideAdapter, provideUtility
39 from zope.component import adapts
40 from zope.component import getUtility, queryUtility
41 from zope.component import getSiteManager
43 from zope.interface import alsoProvides, implements, providedBy
44 from zope.interface import Interface, Attribute
46 from paula.testing import interact
48 class Mock(object):
49 """a mock object that carries desired interfaces
51 >>> class IA(Interface):
52 ... pass
54 >>> class IB(Interface):
55 ... pass
57 >>> m = Mock( a = 1, f = lambda : 2, alsoProvides=(IA,IB))
58 >>> m.a
60 >>> m.f()
62 >>> IA.providedBy(m)
63 True
64 """
65 implements(Interface)
66 def __init__(self, **kwargs):
67 if kwargs.has_key('alsoProvides'):
68 alsoProvides(self, *kwargs['alsoProvides'])
69 del kwargs['alsoProvides']
70 for k,v in kwargs.items():
71 setattr(self, k, v)
73 test_globs = dict(
74 Attribute = Attribute,
75 Interface = Interface,
76 Mock = Mock,
77 UserDict = UserDict,
78 UserList = UserList,
79 adapts = adapts,
80 alsoProvides = alsoProvides,
81 getUtility = getUtility,
82 getSiteManager = getSiteManager,
83 interact = interact.interact,
84 implements = implements,
85 provideAdapter = provideAdapter,
86 provideUtility = provideUtility,
87 providedBy = providedBy,
88 queryUtility = queryUtility,
91 def setUp(test):
92 """We can use this to set up anything that needs to be available for
93 each test. It is run before each test, i.e. for each docstring that
94 contains doctests.
96 Look at the Python unittest and doctest module documentation to learn
97 more about how to prepare state and pass it into various tests.
99 >>> m = Mock()
100 >>> class IA(Interface):
101 ... pass
103 >>> alsoProvides(m, IA)
104 >>> providedBy(m) is not None
105 True
107 >>> provideUtility(m, IA)
109 >>> class A(object):
110 ... adapts(Interface)
111 ... implements(IA)
113 >>> provideAdapter(A)
115 testing.setUp(test)
116 for k,v in test_globs.items():
117 test.globs[k] = v
120 def tearDown(test):
123 testing.tearDown(test)
126 def my_import(name):
127 mod = __import__(name)
128 components = name.split('.')
129 for x in components[1:]:
130 mod = getattr(mod, x)
131 return mod
134 def recurse(*args):
135 """returns all modules, that contain doctests
137 returns all doctests found within the modules passed in *args
139 For paula.testing itself, recurse should find 8 modules containing tests:
141 >>> to_test = recurse('paula.testing')
142 >>> len(to_test)
145 result = []
146 for name in args:
147 mod = my_import(name)
148 result += [mod]
149 modname = mod.__file__.replace('.pyc','').replace('.py','')
150 if modname.endswith('__init__'):
151 # a subpackage
152 dirname = os.path.dirname(mod.__file__)
153 dirlist = os.listdir(dirname)
154 # iterate over content of current directory
155 for x in dirlist:
156 fullpath = os.path.join(dirname, x)
157 # if neither directory nor .py file, skip it
158 if not (os.path.isdir(fullpath) or x.endswith('.py')):
159 continue
161 # skip directories, that are not packages
162 if os.path.isdir(fullpath) and not \
163 os.path.isfile(os.path.join(fullpath, '__init__.py')):
164 continue
166 # get rid of .py ending
167 x = x.replace('.py','')
169 # skip if it starts with a dot
170 if x.startswith('.'):
171 continue
173 # skip __init__.py, it _is_ the current package, which was
174 # added above: result += [mod]
175 if x == "__init__":
176 continue
178 # don't test tests/ and tests.py, XXX: why not?
179 #if x == "tests":
180 # continue
182 mod_name = '%s.%s' % (name, x)
183 result += recurse(mod_name)
184 return result
187 # XXX: this could be moved inside the SuiteGenerator
188 def get_test_suite(pkg_name, tests=[]):
189 """construct a test suite for a package
191 recurses through a package and returns a test suite consisting of all
192 doctest found + the tests passed as argument
194 def test_suite():
195 to_test = recurse(pkg_name,)
196 optionflags = \
197 doctest.REPORT_ONLY_FIRST_FAILURE + \
198 doctest.ELLIPSIS + \
199 doctest.NORMALIZE_WHITESPACE
200 unit_tests = []
201 for x in to_test:
202 unit_test = doctestunit.DocTestSuite(x,
203 setUp=setUp, tearDown=tearDown,
204 optionflags=optionflags
206 unit_tests.append(unit_test)
207 test_suite = unittest.TestSuite(unit_tests + tests)
208 return test_suite
210 return test_suite
213 # TestSuite/Cases loading ftesting.zcml
214 # taken from a zopeproject generated testing.py - thank you
216 #ftesting_zcml = os.path.join(os.path.dirname(__file__), 'ftesting.zcml')
217 #FunctionalLayer = ZCMLLayer(ftesting_zcml, __name__, 'FunctionalLayer')
219 class SuiteGenerator(object):
222 def __init__(self, package_name):
223 self.package_name = package_name
224 self.package = my_import(package_name)
225 self.package_dir = os.path.dirname(self.package.__file__)
226 self.ftesting_zcml = os.path.join(self.package_dir, 'ftesting.zcml')
227 try:
228 self.FunctionalLayer = ZCMLLayer(
229 self.ftesting_zcml,
230 package_name,
231 'FunctionalLayer',
232 allow_teardown=True,
234 except TypeError:
235 self.FunctionalLayer = ZCMLLayer(
236 self.ftesting_zcml,
237 package_name,
238 'FunctionalLayer',
241 @property
242 def FunctionalDocFileSuite(self):
244 def myFunctionalDocFileSuite(path, **kw):
245 if not 'package' in kw:
246 kw['package'] = self.package_name
247 suite = FunctionalDocFileSuite(path, globs=test_globs, **kw)
248 suite.layer = self.FunctionalLayer
249 return suite
251 return myFunctionalDocFileSuite
255 # we currently don't care about these
257 #class FunctionalTestCase(FunctionalTestCase):
258 # layer = FunctionalLayer
261 #def FunctionalDocTestSuite(module=None, **kw):
262 # module = doctest._normalize_module(module)
263 # suite = FunctionalDocTestSuite(module, globs=test_globs, **kw)
264 # suite.layer = FunctionalLayer
265 # return suite