Merge lp:~jamesh/storm/bug-331905-test-runner into lp:storm

Proposed by James Henstridge
Status: Merged
Merged at revision: not available
Proposed branch: lp:~jamesh/storm/bug-331905-test-runner
Merge into: lp:storm
Diff against target: 337 lines (+43/-226)
3 files modified
test (+40/-93)
tests/conftest.py (+0/-133)
tests/helper.py (+3/-0)
To merge this branch: bzr merge lp:~jamesh/storm/bug-331905-test-runner
Reviewer Review Type Date Requested Status
Thomas Herve (community) Approve
Jamu Kakar (community) Approve
Review via email: mp+10106@code.launchpad.net
To post a comment you must log in.
Revision history for this message
James Henstridge (jamesh) wrote :

Clean up the test harness a bit.

* Remove support for running the tests under py.test, as it appears to have broken a while back with no one noticing.
* Collect tests in the same way for both the pyunit and trial test runners. This should also allow Trial to handle the doctests.

Revision history for this message
Jamu Kakar (jkakar) wrote :

Thanks for this, +1!

review: Approve
Revision history for this message
Thomas Herve (therve) wrote :

One flake: test:25: 'new' imported but unused.

+1!

review: Approve
331. By James Henstridge

Remove unneeded import of "new" module.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'test'
2--- test 2009-03-05 21:53:12 +0000
3+++ test 2009-11-09 03:29:09 +0000
4@@ -22,7 +22,6 @@
5 import optparse
6 import unittest
7 import doctest
8-import new
9 import sys
10 import os
11
12@@ -35,14 +34,12 @@
13 @param testpaths: If provided, only tests in the given sequence will
14 be considered. If not provided, all tests are
15 considered.
16- @return: (unittests, doctests) tuple, with lists of unittests and
17- doctests found, respectively.
18+ @return: a test suite containing the requested tests.
19 """
20+ suite = unittest.TestSuite()
21 topdir = os.path.abspath(os.path.dirname(__file__))
22 testdir = os.path.dirname(tests.__file__)
23 testpaths = set(testpaths)
24- unittests = []
25- doctests = []
26 for root, dirnames, filenames in os.walk(testdir):
27 for filename in filenames:
28 filepath = os.path.join(root, filename)
29@@ -62,17 +59,28 @@
30 continue
31
32 if filename.endswith(".py"):
33- unittests.append(relpath)
34- elif relpath == os.path.join("tests", "zope", "README.txt"):
35- # Special case the inclusion of the Zope-dependent
36- # ZStorm doctest.
37- from tests.zope import has_zope
38- if has_zope:
39- doctests.append(relpath)
40+ modpath = relpath.replace(os.path.sep, ".")[:-3]
41+ module = __import__(modpath, None, None, [""])
42+ suite.addTest(
43+ unittest.defaultTestLoader.loadTestsFromModule(module))
44 elif filename.endswith(".txt"):
45- doctests.append(relpath)
46+ load_test = True
47+ if relpath == os.path.join("tests", "zope", "README.txt"):
48+ # Special case the inclusion of the Zope-dependent
49+ # ZStorm doctest.
50+ from tests.zope import has_zope
51+ load_test = has_zope
52+ if load_test:
53+ parent_path = os.path.dirname(relpath).replace(
54+ os.path.sep, ".")
55+ parent_module = __import__(parent_path, None, None, [""])
56+ suite.addTest(doctest.DocFileSuite(
57+ os.path.basename(relpath),
58+ module_relative=True,
59+ package=parent_module,
60+ optionflags=doctest.ELLIPSIS))
61
62- return unittests, doctests
63+ return suite
64
65
66 def parse_sys_argv():
67@@ -85,27 +93,7 @@
68 del sys.argv[i]
69 return testpaths
70
71-
72-def test_with_trial():
73- from twisted.scripts import trial
74- unittests, doctests = find_tests(parse_sys_argv())
75- sys.argv.extend(unittests)
76- trial.run()
77-
78-
79-def test_with_py_test():
80- import py
81- dirname = os.path.dirname(__file__)
82- unittests, doctests = find_tests(parse_sys_argv())
83- sys.argv.extend(unittests)
84- sys.argv.extend(doctests)
85- # For timestamp checking when looping:
86- sys.argv.append(os.path.join(os.path.dirname(__file__), "storm/"))
87- py.test.cmdline.main()
88-
89-
90-def test_with_unittest():
91-
92+def test_with_runner(runner):
93 usage = "test.py [options] [<test filename>, ...]"
94
95 parser = optparse.OptionParser(usage=usage)
96@@ -113,66 +101,25 @@
97 parser.add_option('--verbose', action='store_true')
98 opts, args = parser.parse_args()
99
100- runner = unittest.TextTestRunner()
101-
102 if opts.verbose:
103 runner.verbosity = 2
104
105- loader = unittest.TestLoader()
106-
107- unittests, doctests = find_tests(args)
108-
109- class Summary:
110- def __init__(self):
111- self.total_failures = 0
112- self.total_errors = 0
113- self.total_tests = 0
114- def __call__(self, tests, failures, errors):
115- self.total_tests += tests
116- self.total_failures += failures
117- self.total_errors += errors
118- sys.stderr.write("(tests=%d, failures=%d, errors=%d)\n" %
119- (tests, failures, errors))
120-
121- unittest_summary = Summary()
122- doctest_summary = Summary()
123-
124- if unittests:
125- sys.stderr.write("Running unittests...\n")
126- for relpath in unittests:
127- sys.stderr.write("[%s]\n" % relpath)
128- modpath = relpath.replace(os.path.sep, '.')[:-3]
129- module = __import__(modpath, None, None, [""])
130- test = loader.loadTestsFromModule(module)
131- result = runner.run(test)
132- unittest_summary(test.countTestCases(),
133- len(result.failures), len(result.errors))
134- sys.stderr.write("\n")
135-
136- if doctests:
137- sys.stderr.write("Running doctests...\n")
138- doctest_flags = doctest.ELLIPSIS
139- for relpath in doctests:
140- sys.stderr.write("[%s]\n" % relpath)
141- failures, total = doctest.testfile(relpath,
142- optionflags=doctest_flags)
143- doctest_summary(total, failures, 0)
144- sys.stderr.write("\n")
145-
146- sys.stderr.write("Total test cases: %d\n" % unittest_summary.total_tests)
147- sys.stderr.write("Total doctests: %d\n" % doctest_summary.total_tests)
148- sys.stderr.write("Total failures: %d\n" %
149- (unittest_summary.total_failures +
150- doctest_summary.total_failures))
151- sys.stderr.write("Total errors: %d\n" % (unittest_summary.total_errors +
152- doctest_summary.total_errors))
153-
154- failed = bool(unittest_summary.total_failures or
155- unittest_summary.total_errors or
156- doctest_summary.total_failures or
157- doctest_summary.total_errors)
158-
159- sys.exit(failed)
160+ suite = find_tests(args)
161+ result = runner.run(suite)
162+ return not result.wasSuccessful()
163+
164+
165+def test_with_trial():
166+ from twisted.trial.reporter import TreeReporter
167+ from twisted.trial.runner import TrialRunner
168+ runner = TrialRunner(reporterFactory=TreeReporter, realTimeErrors=True)
169+ return test_with_runner(runner)
170+
171+
172+def test_with_unittest():
173+ runner = unittest.TextTestRunner()
174+ return test_with_runner(runner)
175+
176
177 if __name__ == "__main__":
178 runner = os.environ.get("STORM_TEST_RUNNER")
179@@ -181,6 +128,6 @@
180 runner_func = globals().get("test_with_%s" % runner.replace(".", "_"))
181 if not runner_func:
182 sys.exit("Test runner not found: %s" % runner)
183- runner_func()
184+ sys.exit(runner_func())
185
186 # vim:ts=4:sw=4:et
187
188=== removed file 'tests/conftest.py'
189--- tests/conftest.py 2007-07-06 16:37:49 +0000
190+++ tests/conftest.py 1970-01-01 00:00:00 +0000
191@@ -1,133 +0,0 @@
192-#
193-# Copyright (c) 2006, 2007 Canonical
194-#
195-# Written by Gustavo Niemeyer <gustavo@niemeyer.net>
196-#
197-# This file is part of Storm Object Relational Mapper.
198-#
199-# Storm is free software; you can redistribute it and/or modify
200-# it under the terms of the GNU Lesser General Public License as
201-# published by the Free Software Foundation; either version 2.1 of
202-# the License, or (at your option) any later version.
203-#
204-# Storm is distributed in the hope that it will be useful,
205-# but WITHOUT ANY WARRANTY; without even the implied warranty of
206-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
207-# GNU Lesser General Public License for more details.
208-#
209-# You should have received a copy of the GNU Lesser General Public License
210-# along with this program. If not, see <http://www.gnu.org/licenses/>.
211-#
212-"""
213-Machinery to make py.test interpret standard unittest.TestCase classes.
214-"""
215-from unittest import TestCase, TestResult
216-import doctest
217-import sys
218-
219-import py.test.collect
220-import py.test.compat
221-import py.test
222-
223-
224-class PyTestResult(TestResult):
225- def addFailure(self, test, exc_info):
226- traceback = exc_info[2]
227- while traceback.tb_next:
228- traceback = traceback.tb_next
229- locals = traceback.tb_frame.f_locals
230- if "msg" in locals or "excClass" in locals:
231- locals["__tracebackhide__"] = True
232- msg = str(exc_info[1])
233- if not msg:
234- if "expr" in locals and "msg" in locals:
235- msg = repr(locals["expr"])
236- else:
237- msg = "!?"
238- raise py.test.Item.Failed, py.test.Item.Failed(msg=msg), exc_info[2]
239- addError = addFailure
240-
241-class PyTestCase(TestCase):
242- def __init__(self, methodName="setUp"):
243- super(PyTestCase, self).__init__(methodName)
244-
245- class Function(py.test.Function):
246- def execute(self, target, *args):
247- __tracebackhide__ = True
248- self = target.im_self
249- self.__init__(target.__name__)
250- self.run(PyTestResult())
251-
252-class PyDocTest(py.test.collect.Module):
253- def __init__(self, fspath, parent=None):
254- super(PyDocTest, self).__init__(fspath.basename, parent)
255- self.fspath = fspath
256- self._obj = None
257-
258- def run(self):
259- return [self.name]
260-
261- def join(self, name):
262- return self.Function(name, parent=self, obj=self.fspath)
263-
264- class Function(py.test.Function):
265- def getpathlineno(self):
266- code = py.code.Code(self.failed)
267- return code.path, code.firstlineno
268-
269- def failed(self, msg):
270- raise self.Failed(msg)
271-
272- def execute(self, fspath):
273- failures, total = doctest.testfile(str(fspath),
274- module_relative=False,
275- optionflags=doctest.ELLIPSIS)
276- if failures:
277- __tracebackhide__ = True
278- self.failed("%d doctest cases" % failures)
279-
280-class UnitTestModule(py.test.collect.Module):
281- def buildname2items(self):
282- d = {}
283- for name in dir(self.obj):
284- testclass = None
285- obj = getattr(self.obj, name)
286-
287- try:
288- if issubclass(obj, (TestCase, PyTestCase)):
289- testclass = obj
290- except TypeError:
291- pass
292-
293- if testclass:
294- d[name] = self.Class(name, parent=self)
295- if not issubclass(testclass, PyTestCase):
296- queue = [testclass]
297- while queue:
298- testclass = queue.pop(0)
299- if TestCase in testclass.__bases__:
300- bases = list(testclass.__bases__)
301- bases[bases.index(TestCase)] = PyTestCase
302- testclass.__bases__ = tuple(bases)
303- break
304- queue.extend(testclass.__bases__)
305- return d
306-
307-class UnitTestDirectory(py.test.collect.Directory):
308- def __init__(self, *args, **kwargs):
309- if getattr(self.__class__, "__first_run__", True):
310- self.__class__.__first_run__ = False
311- super(UnitTestDirectory, self).__init__(*args, **kwargs)
312-
313- def filefilter(self, path):
314- return path.check(fnmatch="*.py") and path.basename != "conftest.py"
315-
316- def makeitem(self, basename, filefilter=None, recfilter=None):
317- path = self.fspath.join(basename)
318- if path.check(fnmatch="*.txt"):
319- return PyDocTest(path, parent=self)
320- return super(UnitTestDirectory, self).makeitem(basename,
321- filefilter, recfilter)
322-
323-Module = UnitTestModule
324-Directory = UnitTestDirectory
325
326=== modified file 'tests/helper.py'
327--- tests/helper.py 2008-10-02 15:47:18 +0000
328+++ tests/helper.py 2009-11-09 03:29:09 +0000
329@@ -67,6 +67,9 @@
330 break
331 is_supported = getattr(self, "is_supported", None)
332 if is_supported is not None and not is_supported():
333+ if hasattr(result, "addSkip"):
334+ result.startTest(self)
335+ result.addSkip(self, "Test not supported")
336 return
337 unittest.TestCase.run(self, result)
338

Subscribers

People subscribed via source and target branches

to status/vote changes: