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
=== modified file 'test'
--- test 2009-03-05 21:53:12 +0000
+++ test 2009-11-09 03:29:09 +0000
@@ -22,7 +22,6 @@
22import optparse22import optparse
23import unittest23import unittest
24import doctest24import doctest
25import new
26import sys25import sys
27import os26import os
2827
@@ -35,14 +34,12 @@
35 @param testpaths: If provided, only tests in the given sequence will34 @param testpaths: If provided, only tests in the given sequence will
36 be considered. If not provided, all tests are35 be considered. If not provided, all tests are
37 considered.36 considered.
38 @return: (unittests, doctests) tuple, with lists of unittests and37 @return: a test suite containing the requested tests.
39 doctests found, respectively.
40 """38 """
39 suite = unittest.TestSuite()
41 topdir = os.path.abspath(os.path.dirname(__file__))40 topdir = os.path.abspath(os.path.dirname(__file__))
42 testdir = os.path.dirname(tests.__file__)41 testdir = os.path.dirname(tests.__file__)
43 testpaths = set(testpaths)42 testpaths = set(testpaths)
44 unittests = []
45 doctests = []
46 for root, dirnames, filenames in os.walk(testdir):43 for root, dirnames, filenames in os.walk(testdir):
47 for filename in filenames:44 for filename in filenames:
48 filepath = os.path.join(root, filename)45 filepath = os.path.join(root, filename)
@@ -62,17 +59,28 @@
62 continue59 continue
6360
64 if filename.endswith(".py"):61 if filename.endswith(".py"):
65 unittests.append(relpath)62 modpath = relpath.replace(os.path.sep, ".")[:-3]
66 elif relpath == os.path.join("tests", "zope", "README.txt"):63 module = __import__(modpath, None, None, [""])
67 # Special case the inclusion of the Zope-dependent64 suite.addTest(
68 # ZStorm doctest.65 unittest.defaultTestLoader.loadTestsFromModule(module))
69 from tests.zope import has_zope
70 if has_zope:
71 doctests.append(relpath)
72 elif filename.endswith(".txt"):66 elif filename.endswith(".txt"):
73 doctests.append(relpath)67 load_test = True
68 if relpath == os.path.join("tests", "zope", "README.txt"):
69 # Special case the inclusion of the Zope-dependent
70 # ZStorm doctest.
71 from tests.zope import has_zope
72 load_test = has_zope
73 if load_test:
74 parent_path = os.path.dirname(relpath).replace(
75 os.path.sep, ".")
76 parent_module = __import__(parent_path, None, None, [""])
77 suite.addTest(doctest.DocFileSuite(
78 os.path.basename(relpath),
79 module_relative=True,
80 package=parent_module,
81 optionflags=doctest.ELLIPSIS))
7482
75 return unittests, doctests83 return suite
7684
7785
78def parse_sys_argv():86def parse_sys_argv():
@@ -85,27 +93,7 @@
85 del sys.argv[i]93 del sys.argv[i]
86 return testpaths94 return testpaths
8795
8896def test_with_runner(runner):
89def test_with_trial():
90 from twisted.scripts import trial
91 unittests, doctests = find_tests(parse_sys_argv())
92 sys.argv.extend(unittests)
93 trial.run()
94
95
96def test_with_py_test():
97 import py
98 dirname = os.path.dirname(__file__)
99 unittests, doctests = find_tests(parse_sys_argv())
100 sys.argv.extend(unittests)
101 sys.argv.extend(doctests)
102 # For timestamp checking when looping:
103 sys.argv.append(os.path.join(os.path.dirname(__file__), "storm/"))
104 py.test.cmdline.main()
105
106
107def test_with_unittest():
108
109 usage = "test.py [options] [<test filename>, ...]"97 usage = "test.py [options] [<test filename>, ...]"
11098
111 parser = optparse.OptionParser(usage=usage)99 parser = optparse.OptionParser(usage=usage)
@@ -113,66 +101,25 @@
113 parser.add_option('--verbose', action='store_true')101 parser.add_option('--verbose', action='store_true')
114 opts, args = parser.parse_args()102 opts, args = parser.parse_args()
115103
116 runner = unittest.TextTestRunner()
117
118 if opts.verbose:104 if opts.verbose:
119 runner.verbosity = 2105 runner.verbosity = 2
120106
121 loader = unittest.TestLoader()107 suite = find_tests(args)
122108 result = runner.run(suite)
123 unittests, doctests = find_tests(args)109 return not result.wasSuccessful()
124110
125 class Summary:111
126 def __init__(self):112def test_with_trial():
127 self.total_failures = 0113 from twisted.trial.reporter import TreeReporter
128 self.total_errors = 0114 from twisted.trial.runner import TrialRunner
129 self.total_tests = 0115 runner = TrialRunner(reporterFactory=TreeReporter, realTimeErrors=True)
130 def __call__(self, tests, failures, errors):116 return test_with_runner(runner)
131 self.total_tests += tests117
132 self.total_failures += failures118
133 self.total_errors += errors119def test_with_unittest():
134 sys.stderr.write("(tests=%d, failures=%d, errors=%d)\n" %120 runner = unittest.TextTestRunner()
135 (tests, failures, errors))121 return test_with_runner(runner)
136122
137 unittest_summary = Summary()
138 doctest_summary = Summary()
139
140 if unittests:
141 sys.stderr.write("Running unittests...\n")
142 for relpath in unittests:
143 sys.stderr.write("[%s]\n" % relpath)
144 modpath = relpath.replace(os.path.sep, '.')[:-3]
145 module = __import__(modpath, None, None, [""])
146 test = loader.loadTestsFromModule(module)
147 result = runner.run(test)
148 unittest_summary(test.countTestCases(),
149 len(result.failures), len(result.errors))
150 sys.stderr.write("\n")
151
152 if doctests:
153 sys.stderr.write("Running doctests...\n")
154 doctest_flags = doctest.ELLIPSIS
155 for relpath in doctests:
156 sys.stderr.write("[%s]\n" % relpath)
157 failures, total = doctest.testfile(relpath,
158 optionflags=doctest_flags)
159 doctest_summary(total, failures, 0)
160 sys.stderr.write("\n")
161
162 sys.stderr.write("Total test cases: %d\n" % unittest_summary.total_tests)
163 sys.stderr.write("Total doctests: %d\n" % doctest_summary.total_tests)
164 sys.stderr.write("Total failures: %d\n" %
165 (unittest_summary.total_failures +
166 doctest_summary.total_failures))
167 sys.stderr.write("Total errors: %d\n" % (unittest_summary.total_errors +
168 doctest_summary.total_errors))
169
170 failed = bool(unittest_summary.total_failures or
171 unittest_summary.total_errors or
172 doctest_summary.total_failures or
173 doctest_summary.total_errors)
174
175 sys.exit(failed)
176123
177if __name__ == "__main__":124if __name__ == "__main__":
178 runner = os.environ.get("STORM_TEST_RUNNER")125 runner = os.environ.get("STORM_TEST_RUNNER")
@@ -181,6 +128,6 @@
181 runner_func = globals().get("test_with_%s" % runner.replace(".", "_"))128 runner_func = globals().get("test_with_%s" % runner.replace(".", "_"))
182 if not runner_func:129 if not runner_func:
183 sys.exit("Test runner not found: %s" % runner)130 sys.exit("Test runner not found: %s" % runner)
184 runner_func()131 sys.exit(runner_func())
185132
186# vim:ts=4:sw=4:et133# vim:ts=4:sw=4:et
187134
=== removed file 'tests/conftest.py'
--- tests/conftest.py 2007-07-06 16:37:49 +0000
+++ tests/conftest.py 1970-01-01 00:00:00 +0000
@@ -1,133 +0,0 @@
1#
2# Copyright (c) 2006, 2007 Canonical
3#
4# Written by Gustavo Niemeyer <gustavo@niemeyer.net>
5#
6# This file is part of Storm Object Relational Mapper.
7#
8# Storm is free software; you can redistribute it and/or modify
9# it under the terms of the GNU Lesser General Public License as
10# published by the Free Software Foundation; either version 2.1 of
11# the License, or (at your option) any later version.
12#
13# Storm is distributed in the hope that it will be useful,
14# but WITHOUT ANY WARRANTY; without even the implied warranty of
15# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16# GNU Lesser General Public License for more details.
17#
18# You should have received a copy of the GNU Lesser General Public License
19# along with this program. If not, see <http://www.gnu.org/licenses/>.
20#
21"""
22Machinery to make py.test interpret standard unittest.TestCase classes.
23"""
24from unittest import TestCase, TestResult
25import doctest
26import sys
27
28import py.test.collect
29import py.test.compat
30import py.test
31
32
33class PyTestResult(TestResult):
34 def addFailure(self, test, exc_info):
35 traceback = exc_info[2]
36 while traceback.tb_next:
37 traceback = traceback.tb_next
38 locals = traceback.tb_frame.f_locals
39 if "msg" in locals or "excClass" in locals:
40 locals["__tracebackhide__"] = True
41 msg = str(exc_info[1])
42 if not msg:
43 if "expr" in locals and "msg" in locals:
44 msg = repr(locals["expr"])
45 else:
46 msg = "!?"
47 raise py.test.Item.Failed, py.test.Item.Failed(msg=msg), exc_info[2]
48 addError = addFailure
49
50class PyTestCase(TestCase):
51 def __init__(self, methodName="setUp"):
52 super(PyTestCase, self).__init__(methodName)
53
54 class Function(py.test.Function):
55 def execute(self, target, *args):
56 __tracebackhide__ = True
57 self = target.im_self
58 self.__init__(target.__name__)
59 self.run(PyTestResult())
60
61class PyDocTest(py.test.collect.Module):
62 def __init__(self, fspath, parent=None):
63 super(PyDocTest, self).__init__(fspath.basename, parent)
64 self.fspath = fspath
65 self._obj = None
66
67 def run(self):
68 return [self.name]
69
70 def join(self, name):
71 return self.Function(name, parent=self, obj=self.fspath)
72
73 class Function(py.test.Function):
74 def getpathlineno(self):
75 code = py.code.Code(self.failed)
76 return code.path, code.firstlineno
77
78 def failed(self, msg):
79 raise self.Failed(msg)
80
81 def execute(self, fspath):
82 failures, total = doctest.testfile(str(fspath),
83 module_relative=False,
84 optionflags=doctest.ELLIPSIS)
85 if failures:
86 __tracebackhide__ = True
87 self.failed("%d doctest cases" % failures)
88
89class UnitTestModule(py.test.collect.Module):
90 def buildname2items(self):
91 d = {}
92 for name in dir(self.obj):
93 testclass = None
94 obj = getattr(self.obj, name)
95
96 try:
97 if issubclass(obj, (TestCase, PyTestCase)):
98 testclass = obj
99 except TypeError:
100 pass
101
102 if testclass:
103 d[name] = self.Class(name, parent=self)
104 if not issubclass(testclass, PyTestCase):
105 queue = [testclass]
106 while queue:
107 testclass = queue.pop(0)
108 if TestCase in testclass.__bases__:
109 bases = list(testclass.__bases__)
110 bases[bases.index(TestCase)] = PyTestCase
111 testclass.__bases__ = tuple(bases)
112 break
113 queue.extend(testclass.__bases__)
114 return d
115
116class UnitTestDirectory(py.test.collect.Directory):
117 def __init__(self, *args, **kwargs):
118 if getattr(self.__class__, "__first_run__", True):
119 self.__class__.__first_run__ = False
120 super(UnitTestDirectory, self).__init__(*args, **kwargs)
121
122 def filefilter(self, path):
123 return path.check(fnmatch="*.py") and path.basename != "conftest.py"
124
125 def makeitem(self, basename, filefilter=None, recfilter=None):
126 path = self.fspath.join(basename)
127 if path.check(fnmatch="*.txt"):
128 return PyDocTest(path, parent=self)
129 return super(UnitTestDirectory, self).makeitem(basename,
130 filefilter, recfilter)
131
132Module = UnitTestModule
133Directory = UnitTestDirectory
1340
=== modified file 'tests/helper.py'
--- tests/helper.py 2008-10-02 15:47:18 +0000
+++ tests/helper.py 2009-11-09 03:29:09 +0000
@@ -67,6 +67,9 @@
67 break67 break
68 is_supported = getattr(self, "is_supported", None)68 is_supported = getattr(self, "is_supported", None)
69 if is_supported is not None and not is_supported():69 if is_supported is not None and not is_supported():
70 if hasattr(result, "addSkip"):
71 result.startTest(self)
72 result.addSkip(self, "Test not supported")
70 return73 return
71 unittest.TestCase.run(self, result)74 unittest.TestCase.run(self, result)
7275

Subscribers

People subscribed via source and target branches

to status/vote changes: