TextTestRunner
不知道如何翻译这个单词才好,我就叫它文本类测试用例运行器吧,大概就这个意思。
通过前两篇对TestCase和TestSuite类的详解,我们都知道他们都有一个自己的run方法,其实我们可以直接调用他们各自的run方法就可以执行我们的测试用例或测试集了,我们只需要初始化一个TestResult类或者其子类的实例传入到第一个参数即可,比如:
import sys
import unittest
class UserCase(unittest.TestCase):
def testAddUser(self):
print("add a user")
def testDelUser(self):
print("delete a user")
if __name__ == '__main__':
result = unittest.TextTestResult(sys.stdout,'test result',1)
testcase = UserCase('testAddUser')
testcase.run(result) #我们只需要传入一个result对象即可
那何必还需要一个TextTestRunner类呢,个人觉得主要是为了控制测试结果的输出,为什么这么说呢,大家可以自己动手实践一下,对比一下直接使用TestCase的run方法运行后的结果和通过TextTestRunner的run方法运行的结果输出有什么不同。扩展HTMLTestRunner大神,其扩展的主要也就是TestRunner部分(当然还有扩展TestResult)使其结果输出为HTML的报告,所以想要自定义的控制测试结果(即result)的输出,可以从扩展TestRunner这里入手。
我们先来看一下我们自己写代码时用TextTestRunner是怎么去执行用例的。
import unittest
class UserCase(unittest.TestCase):
def testAddUser(self):
print("add a user")
def testDelUser(self):
print("delete a user")
if __name__ == '__main__':
runner = unittest.TextTestRunner()
suite = unittest.TestSuite(map(UserCase,['testAddUser','testDelUser']))
case = UserCase('testAddUser')
runner.run(suite)
runner.run(case)
从代码里面可以看到我们是通过TextTestRunner类实例的run方法去执行的用例或用例集。下面我们来分析一下run方法:
def run(self, test):
"Run the given test case or test suite."
result = self._makeResult()
registerResult(result)
result.failfast = self.failfast
result.buffer = self.buffer
startTime = time.time()
startTestRun = getattr(result, 'startTestRun', None)
if startTestRun is not None:
startTestRun()
try:
test(result)
finally:
stopTestRun = getattr(result, 'stopTestRun', None)
if stopTestRun is not None:
stopTestRun()
stopTime = time.time()
timeTaken = stopTime - startTime
result.printErrors()
if hasattr(result, 'separator2'):
self.stream.writeln(result.separator2)
run = result.testsRun
self.stream.writeln("Ran %d test%s in %.3fs" %
(run, run != 1 and "s" or "", timeTaken))
self.stream.writeln()
expectedFails = unexpectedSuccesses = skipped = 0
try:
results = map(len, (result.expectedFailures,
result.unexpectedSuccesses,
result.skipped))
except AttributeError:
pass
else:
expectedFails, unexpectedSuccesses, skipped = results
infos = []
if not result.wasSuccessful():
self.stream.write("FAILED")
failed, errored = map(len, (result.failures, result.errors))
if failed:
infos.append("failures=%d" % failed)
if errored:
infos.append("errors=%d" % errored)
else:
self.stream.write("OK")
if skipped:
infos.append("skipped=%d" % skipped)
if expectedFails:
infos.append("expected failures=%d" % expectedFails)
if unexpectedSuccesses:
infos.append("unexpected successes=%d" % unexpectedSuccesses)
if infos:
self.stream.writeln(" (%s)" % (", ".join(infos),))
else:
self.stream.write("\n")
return result
其实这么长一段的代码,最重要的一行代码是:test(result),其中test是我们传入的TestCase类的实例或TestSuite类的实例,所以这句代码最终调用的就是TestCase类的run方法或TestSuite类的run方法,而这两个run方法就在我前两篇文章分析的内容里面,忘记的朋友可以回到前面再去阅读一番。
对于其他部分的代码,分析起来就太多了,基本都是处理result的内容(即测试结果数据的处理),这里也暂时不做详细的分析了