Merge lp://staging/~jamesh/storm/bug-331905-test-runner into lp://staging/storm
- bug-331905-test-runner
- Merge into trunk
Proposed by
James Henstridge
Status: | Merged |
---|---|
Merged at revision: | not available |
Proposed branch: | lp://staging/~jamesh/storm/bug-331905-test-runner |
Merge into: | lp://staging/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://staging/~jamesh/storm/bug-331905-test-runner |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Thomas Herve (community) | Approve | ||
Jamu Kakar (community) | Approve | ||
Review via email: mp+10106@code.staging.launchpad.net |
Commit message
Description of the change
To post a comment you must log in.
Revision history for this message
James Henstridge (jamesh) wrote : | # |
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 |
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.