此解决方案适用于Python版本2.7到3.7(当前最高版本),在tearDown之前,任何代码中都没有任何修饰或其他修改。一切都是根据结果的内置分类工作的。也可以正确识别跳过的测试或expectedFailure。它评估当前测试的结果,而不是迄今为止通过的所有测试的摘要。也与pytest兼容。import unittest
class MyTest(unittest.TestCase):
def tearDown(self):
if hasattr(self, '_outcome'): # Python 3.4+
result = self.defaultTestResult() # these 2 methods have no side effects
self._feedErrorsToResult(result, self._outcome.errors)
else: # Python 3.2 - 3.3 or 3.0 - 3.1 and 2.7
result = getattr(self, '_outcomeForDoCleanups', self._resultForDoCleanups)
error = self.list2reason(result.errors)
failure = self.list2reason(result.failures)
ok = not error and not failure
# demo: report short info immediately (not important)
if not ok:
typ, text = ('ERROR', error) if error else ('FAIL', failure)
msg = [x for x in text.split('\n')[1:] if not x.startswith(' ')][0]
print("\n%s: %s\n %s" % (typ, self.id(), msg))
def list2reason(self, exc_list):
if exc_list and exc_list[-1][0] is self:
return exc_list[-1][1]
# DEMO tests
def test_success(self):
self.assertEqual(1, 1)
def test_fail(self):
self.assertEqual(2, 1)
def test_error(self):
self.assertEqual(1 / 0, 1)
注释:只有一个或零个异常(错误或失败)需要报告,因为在tearDown之前不需要报告更多异常。包unittest期望第二个异常可以由tearDown引发。因此,列表errors和failures在分解之前只能包含一个或零个元素。“demo”注释后的行将报告一个简短的结果。
演示输出:(不重要)$ python3.5 -m unittest test
EF.
ERROR: test.MyTest.test_error
ZeroDivisionError: division by zero
FAIL: test.MyTest.test_fail
AssertionError: 2 != 1
==========================================================
... skipped usual output from unittest with tracebacks ...
...
Ran 3 tests in 0.002s
FAILED (failures=1, errors=1)
与其他解决方案的比较-(关于Python源库的提交历史):这个解决方案使用TestCase实例的私有属性
其他解决方案,
但是我仔细检查了Python源代码库中所有相关的提交
这三个替代名称涵盖了自Python以来的代码历史
2.7至3.6.2无任何间隙。新主修后可能会有问题
Python版本,但它可以被清楚地识别、跳过并很容易地修复
稍后是一条新的Python。一个优点是以前没有任何修改
运行tearDown,它不应该破坏测试和
unittest是受支持的,与pytest一起工作,它可以工作许多扩展包,但不能与NoTest一起工作(因为NoTest不兼容,例如与unittest.expectedFailure不兼容,所以不是意外)。
在用户测试方法上使用decorators或自定义
failureException(mgilson,Pavel Repin 2nd way,kenorb)对
未来Python
但如果一切都正常的话
雪球有更多支持的例外和更多复制的内部
单位测试。修饰后的函数具有可读性较差的回溯
(由一个decorator添加更多的级别),它们对于
调试,如果另一个更重要的装饰器
有问题。(多亏了mgilson,基本功能已经准备好并为人所知
问题可以解决。)
用modifiedrun方法和catchedresult求解
参数(scoffey)应该可以工作
同样适用于Python2.6。对结果的解释可以改进为
问题的需求,但在Python3.4+中没有任何东西可以工作,
因为result是在拆卸调用之后更新的,以前从未更新过。
标记G:(使用Python2.7、3.2、3.3、3.4和NoTest进行测试)
solution byexc_info()(Pavel Repin 2st way)仅适用于Python 2。
其他的解决方案在原则上是相似的,但是不太完整或者更多
缺点。
由Python源代码库解释
=Lib/unittest/case.py=
Python2.7-3.3版class TestCase(object):
...
def run(self, result=None):
...
self._outcomeForDoCleanups = result # Python 3.2, 3.3
# self._resultForDoCleanups = result # Python 2.7
# # Python 2.6 - no result saved
...
try:
testMethod()
except... # many times for different exception classes
result.add...(self, sys.exc_info()) # _addSkip, addError, addFailure
...
try:
self.tearDown()
...
Python3.4-3.6版def run(self, result=None):
...
# outocome is a context manager to catch and collect different exceptions
self._outcome = outcome
...
with outcome...(self):
testMethod()
...
with outcome...(self):
self.tearDown()
...
self._feedErrorsToResult(result, outcome.errors)
注意(通过读取Python commit消息):测试结果与测试如此脱钩的一个原因是防止内存泄漏。每个异常信息都可以访问失败进程状态的帧,包括所有本地变量。如果一个帧被分配给代码块中的一个局部变量,这个局部变量也可能失败,那么就可以很容易地创建一个跨内存引用。这并不可怕,多亏了垃圾回收器,但是空闲内存碎片化的速度比正确释放内存要快得多。这就是异常信息和回溯很快被转换为字符串的原因,以及像self._outcome这样的临时对象被封装为在finally块中t到None以防止内存泄漏。