Source code for unittest.suite

"""TestSuite"""importsysfrom.importcasefrom.importutil__unittest=Truedef_call_if_exists(parent,attr):func=getattr(parent,attr,lambda:None)func()classBaseTestSuite(object):"""A simple test suite that doesn't provide class or module shared fixtures. """_cleanup=Truedef__init__(self,tests=()):self._tests=[]self._removed_tests=0self.addTests(tests)def__repr__(self):return"<%s tests=%s>"%(util.strclass(self.__class__),list(self))def__eq__(self,other):ifnotisinstance(other,self.__class__):returnNotImplementedreturnlist(self)==list(other)def__iter__(self):returniter(self._tests)defcountTestCases(self):cases=self._removed_testsfortestinself:iftest:cases+=test.countTestCases()returncasesdefaddTest(self,test):# sanity checksifnotcallable(test):raiseTypeError("{} is not callable".format(repr(test)))ifisinstance(test,type)andissubclass(test,(case.TestCase,TestSuite)):raiseTypeError("TestCases and TestSuites must be instantiated ""before passing them to addTest()")self._tests.append(test)defaddTests(self,tests):ifisinstance(tests,str):raiseTypeError("tests must be an iterable of tests, not a string")fortestintests:self.addTest(test)defrun(self,result):forindex,testinenumerate(self):ifresult.shouldStop:breaktest(result)ifself._cleanup:self._removeTestAtIndex(index)returnresultdef_removeTestAtIndex(self,index):"""Stop holding a reference to the TestCase at index."""try:test=self._tests[index]exceptTypeError:# support for suite implementations that have overridden self._testspasselse:# Some unittest tests add non TestCase/TestSuite objects to# the suite.ifhasattr(test,'countTestCases'):self._removed_tests+=test.countTestCases()self._tests[index]=Nonedef__call__(self,*args,**kwds):returnself.run(*args,**kwds)defdebug(self):"""Run the tests without collecting errors in a TestResult"""fortestinself:test.debug()classTestSuite(BaseTestSuite):"""A test suite is a composite test consisting of a number of TestCases. For use, create an instance of TestSuite, then add test case instances. When all tests have been added, the suite can be passed to a test runner, such as TextTestRunner. It will run the individual test cases in the order in which they were added, aggregating the results. When subclassing, do not forget to call the base class constructor. """defrun(self,result,debug=False):topLevel=Falseifgetattr(result,'_testRunEntered',False)isFalse:result._testRunEntered=topLevel=Trueforindex,testinenumerate(self):ifresult.shouldStop:breakif_isnotsuite(test):self._tearDownPreviousClass(test,result)self._handleModuleFixture(test,result)self._handleClassSetUp(test,result)result._previousTestClass=test.__class__if(getattr(test.__class__,'_classSetupFailed',False)orgetattr(result,'_moduleSetUpFailed',False)):continueifnotdebug:test(result)else:test.debug()ifself._cleanup:self._removeTestAtIndex(index)iftopLevel:self._tearDownPreviousClass(None,result)self._handleModuleTearDown(result)result._testRunEntered=Falsereturnresultdefdebug(self):"""Run the tests without collecting errors in a TestResult"""debug=_DebugResult()self.run(debug,True)################################def_handleClassSetUp(self,test,result):previousClass=getattr(result,'_previousTestClass',None)currentClass=test.__class__ifcurrentClass==previousClass:returnifresult._moduleSetUpFailed:returnifgetattr(currentClass,"__unittest_skip__",False):returntry:currentClass._classSetupFailed=FalseexceptTypeError:# test may actually be a function# so its class will be a builtin-typepasssetUpClass=getattr(currentClass,'setUpClass',None)ifsetUpClassisnotNone:_call_if_exists(result,'_setupStdout')try:setUpClass()exceptExceptionase:ifisinstance(result,_DebugResult):raisecurrentClass._classSetupFailed=TrueclassName=util.strclass(currentClass)errorName='setUpClass (%s)'%classNameself._addClassOrModuleLevelException(result,e,errorName)finally:_call_if_exists(result,'_restoreStdout')def_get_previous_module(self,result):previousModule=NonepreviousClass=getattr(result,'_previousTestClass',None)ifpreviousClassisnotNone:previousModule=previousClass.__module__returnpreviousModuledef_handleModuleFixture(self,test,result):previousModule=self._get_previous_module(result)currentModule=test.__class__.__module__ifcurrentModule==previousModule:returnself._handleModuleTearDown(result)result._moduleSetUpFailed=Falsetry:module=sys.modules[currentModule]exceptKeyError:returnsetUpModule=getattr(module,'setUpModule',None)ifsetUpModuleisnotNone:_call_if_exists(result,'_setupStdout')try:setUpModule()exceptExceptionase:ifisinstance(result,_DebugResult):raiseresult._moduleSetUpFailed=TrueerrorName='setUpModule (%s)'%currentModuleself._addClassOrModuleLevelException(result,e,errorName)finally:_call_if_exists(result,'_restoreStdout')def_addClassOrModuleLevelException(self,result,exception,errorName):error=_ErrorHolder(errorName)addSkip=getattr(result,'addSkip',None)ifaddSkipisnotNoneandisinstance(exception,case.SkipTest):addSkip(error,str(exception))else:result.addError(error,sys.exc_info())def_handleModuleTearDown(self,result):previousModule=self._get_previous_module(result)ifpreviousModuleisNone:returnifresult._moduleSetUpFailed:returntry:module=sys.modules[previousModule]exceptKeyError:returntearDownModule=getattr(module,'tearDownModule',None)iftearDownModuleisnotNone:_call_if_exists(result,'_setupStdout')try:tearDownModule()exceptExceptionase:ifisinstance(result,_DebugResult):raiseerrorName='tearDownModule (%s)'%previousModuleself._addClassOrModuleLevelException(result,e,errorName)finally:_call_if_exists(result,'_restoreStdout')def_tearDownPreviousClass(self,test,result):previousClass=getattr(result,'_previousTestClass',None)currentClass=test.__class__ifcurrentClass==previousClass:returnifgetattr(previousClass,'_classSetupFailed',False):returnifgetattr(result,'_moduleSetUpFailed',False):returnifgetattr(previousClass,"__unittest_skip__",False):returntearDownClass=getattr(previousClass,'tearDownClass',None)iftearDownClassisnotNone:_call_if_exists(result,'_setupStdout')try:tearDownClass()exceptExceptionase:ifisinstance(result,_DebugResult):raiseclassName=util.strclass(previousClass)errorName='tearDownClass (%s)'%classNameself._addClassOrModuleLevelException(result,e,errorName)finally:_call_if_exists(result,'_restoreStdout')class_ErrorHolder(object):""" Placeholder for a TestCase inside a result. As far as a TestResult is concerned, this looks exactly like a unit test. Used to insert arbitrary errors into a test suite run. """# Inspired by the ErrorHolder from Twisted:# http://twistedmatrix.com/trac/browser/trunk/twisted/trial/runner.py# attribute used by TestResult._exc_info_to_stringfailureException=Nonedef__init__(self,description):self.description=descriptiondefid(self):returnself.descriptiondefshortDescription(self):returnNonedef__repr__(self):return"<ErrorHolder description=%r>"%(self.description,)def__str__(self):returnself.id()defrun(self,result):# could call result.addError(...) - but this test-like object# shouldn't be run anywaypassdef__call__(self,result):returnself.run(result)defcountTestCases(self):return0def_isnotsuite(test):"A crude way to tell apart testcases and suites with duck-typing"try:iter(test)exceptTypeError:returnTruereturnFalseclass_DebugResult(object):"Used by the TestSuite to hold previous class when running in debug."_previousTestClass=None_moduleSetUpFailed=FalseshouldStop=False