背景
我正在试图找出如何针对多个输入值运行单个unittest,然后显示失败。这是一个关于我想到的事情的简单演示:
from time import time
import unittest
def demo():
while True:
count = 0
for i in xrange(10):
count += 1
yield int(time() * 1000) + count
count = 0
class TestDemo(unittest.TestCase):
def setUp(self):
self.gen = demo()
self.prev = next(self.gen)
def test_always_bigger(self):
for cycle in xrange(1000):
curr = next(self.gen)
self.assertGreater(curr, self.prev)
self.prev = curr
if __name__ == '__main__':
unittest.main()
我发现的最相似的问题已通过某种动态test_<something>
方法创建(例如:1,2,3)或{{3 (例如:nose generators,1)。我期待基于不可预测的输入运行1000次迭代,同时坚持使用标准库,因此这两种解决方案都不适合。简单的循环(如上所示)适用于两个限制:对于复杂的输入,导致测试失败的原因记录不足(我的真正问题);并且,test_<...>
方法中的单个故障未能通过整个测试。
问题
我可以忍受早期的失败,但是如何在输入导致失败的情况下不会在成功时创建数千行输出?
非应答
我尝试了assert...
方法msg
kwarg,但它实际上只适用于图书馆已经很好处理的那些微不足道的案例。在上面的例子中,unittest知道显示导致断言失败的两个long
。我可以使用`self.assertGreater(curr,self.prev,msg =“cycle%s”%cycle)对这个失败进行注释并提供很多洞察,但是在assertDictEquals上显示深层嵌套的dicts是一团糟。
理想的解决方案
这个2显示了日志记录模块的有趣用法,但每次成功测试都会生成数千行输出。是否可以从测试方法中检测出故障?类似的东西:
def test_always_bigger(self):
for cycle in xrange(1000):
curr = next(self.gen)
fail = self.assertGreater(curr, self.prev)
if fail:
log.debug('...')
self.prev = curr
答案 0 :(得分:2)
def test_always_bigger(self):
for cycle in xrange(1000):
curr = next(self.gen)
try:
self.assertGreater(curr, self.prev)
except AssertionError: # raised by TestCase.fail, called by all asserts
log.debug('...')
raise
self.prev = curr
这实现了在出现故障时记录的语义,然后继续失败。如果您想完成所有测试,我会执行以下操作:
def test_always_bigger(self):
ex = None
for cycle in xrange(1000):
curr = next(self.gen)
try:
self.assertGreater(curr, self.prev)
except AssertionError, ae:
ex = ae # just remember it
log.debug('...')
self.prev = curr
if ex:
raise ex
显然,这只会引发第一个AssertionError
,但它会一直运行直到完成,并会独立记录所有故障。由于此函数仅代表框架的一个测试,因此您无法真正产生多个故障。
如果您出于某种原因需要访问所有异常,您可以使用以下内容(未使用unittest
进行彻底测试)
def test_always_bigger(self):
exes = []
for cycle in xrange(1000):
curr = next(self.gen)
try:
self.assertGreater(curr, self.prev)
except AssertionError, ae:
exes.append(ae)
log.debug('...')
self.prev = curr
if exes:
self.fail(exes)
# if that doesn't work, try: raise AssertionError(exes)