--- /usr/lib/python2.5/unittest.py 2006-10-29 12:44:30.000000000 +0100 +++ unittest.py 2006-11-02 22:57:52.458441021 +0100 @@ -208,14 +208,6 @@ raise ValueError, "no such test method in %s: %s" % \ (self.__class__, methodName) - def setUp(self): - "Hook method for setting up the test fixture before exercising it." - pass - - def tearDown(self): - "Hook method for deconstructing the test fixture after testing it." - pass - def countTestCases(self): return 1 @@ -248,7 +240,7 @@ testMethod = getattr(self, self._testMethodName) try: try: - self.setUp() + self._get_setup()() except KeyboardInterrupt: raise except: @@ -267,7 +259,7 @@ result.addError(self, self._exc_info()) try: - self.tearDown() + self._get_teardown()() except KeyboardInterrupt: raise except: @@ -296,6 +288,29 @@ return (exctype, excvalue, tb) return (exctype, excvalue, tb) + def _get_setup(self): + """Return this class's setup method.""" + return self._get_method("setUp", "_unittest_setup") + + def _get_teardown(self): + """Return this class's teardown method.""" + return self._get_method("tearDown", "_unittest_teardown") + + def _get_method(self, methodname, attribute): + """Return this class's method called "methodname", or a method with + the attribute "attribute". If neither exists, returns a noop method.""" + try: + return getattr(self, methodname) + except AttributeError, e: + for attrname in self.__class__.__dict__: + attr = self.__class__.__dict__[attrname] + try: + if getattr(attr, attribute): + return lambda *args, **kwargs: attr(self, *args, **kwargs) + except AttributeError, e: + pass + return lambda: None + def fail(self, msg=None): """Fail immediately, with the given message.""" raise self.failureException, msg @@ -560,7 +575,10 @@ """Return a sorted sequence of method names found within testCaseClass """ def isTestMethod(attrname, testCaseClass=testCaseClass, prefix=self.testMethodPrefix): - return attrname.startswith(prefix) and callable(getattr(testCaseClass, attrname)) + attr = getattr(testCaseClass, attrname) + if attrname.startswith(prefix) and callable(attr): + return True + return hasattr(attr, "_unittest_test") testFnNames = filter(isTestMethod, dir(testCaseClass)) for baseclass in testCaseClass.__bases__: for testFnName in self.getTestCaseNames(baseclass): @@ -718,6 +736,26 @@ ############################################################################## +# Decorators +############################################################################## + +def test(method): + """A decorator for test cases.""" + method._unittest_test = True + return method + +def setup(method): + """A decorator for test setup methods.""" + method._unittest_setup = True + return method + +def teardown(method): + """A decorator for test teardown methods.""" + method._unittest_teardown = True + return method + + +############################################################################## # Facilities for running tests from the command line ##############################################################################