1
# Copyright (C) 2004, 2005, 2006 Canonical Ltd
2
# Author: Robert Collins <robert.collins@canonical.com>
4
# This program is free software; you can redistribute it and/or modify
5
# it under the terms of the GNU General Public License as published by
6
# the Free Software Foundation; either version 2 of the License, or
7
# (at your option) any later version.
9
# This program is distributed in the hope that it will be useful,
10
# but WITHOUT ANY WARRANTY; without even the implied warranty of
11
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
# GNU General Public License for more details.
14
# You should have received a copy of the GNU General Public License
15
# along with this program; if not, write to the Free Software
16
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23
# Mark this python module as being part of the implementation
24
# of unittest: this gives us better tracebacks where the last
25
# shown frame is the test code, not our assertXYZ.
29
class LogCollector(logging.Handler):
31
logging.Handler.__init__(self)
33
def emit(self, record):
34
self.records.append(record.getMessage())
37
def makeCollectingLogger():
38
"""I make a logger instance that collects its logs for programmatic analysis
39
-> (logger, collector)"""
40
logger=logging.Logger("collector")
41
handler=LogCollector()
42
handler.setFormatter(logging.Formatter("%(levelname)s: %(message)s"))
43
logger.addHandler(handler)
44
return logger, handler
47
def visitTests(suite, visitor):
48
"""A foreign method for visiting the tests in a test suite."""
49
for test in suite._tests:
50
#Abusing types to avoid monkey patching unittest.TestCase.
51
# Maybe that would be better?
54
except AttributeError:
55
if isinstance(test, unittest.TestCase):
56
visitor.visitCase(test)
57
elif isinstance(test, unittest.TestSuite):
58
visitor.visitSuite(test)
59
visitTests(test, visitor)
61
print "unvisitable non-unittest.TestCase element %r (%r)" % (test, test.__class__)
64
class TestSuite(unittest.TestSuite):
65
"""I am an extended TestSuite with a visitor interface.
66
This is primarily to allow filtering of tests - and suites or
67
more in the future. An iterator of just tests wouldn't scale..."""
69
def visit(self, visitor):
70
"""visit the composite. Visiting is depth-first.
71
current callbacks are visitSuite and visitCase."""
72
visitor.visitSuite(self)
73
visitTests(self, visitor)
76
class TestLoader(unittest.TestLoader):
77
"""Custom TestLoader to address some quirks in the stock python one."""
78
suiteClass = TestSuite
80
def loadTestsFromModuleNames(self, names):
81
"""use a custom means to load tests from modules.
83
There is an undesirable glitch in the python TestLoader where a
84
import error is ignore. We think this can be solved by ensuring the
85
requested name is resolvable, if its not raising the original error.
87
result = self.suiteClass()
89
_load_module_by_name(name)
90
result.addTests(self.loadTestsFromName(name))
94
def _load_module_by_name(mod_name):
95
parts = mod_name.split('.')
96
module = __import__(mod_name)
98
# for historical reasons python returns the top-level module even though
99
# it loads the submodule; we need to walk down to get the one we want.
101
module = getattr(module, parts.pop(0))
105
class TestVisitor(object):
106
"""A visitor for Tests"""
107
def visitSuite(self, aTestSuite):
109
def visitCase(self, aTestCase):