Python unittest:响应测试方法中的失败

时间:2012-05-03 03:49:05

标签: python unit-testing

背景

我正在试图找出如何针对多个输入值运行单个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>方法创建(例如:123)或{{3 (例如:nose generators1)。我期待基于不可预测的输入运行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

1 个答案:

答案 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)