1

背景

我试图弄清楚如何针对多个输入值运行单个单元测试,然后显示失败。这是我想到的那种事情的一个简单的演示:

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 或鼻子生成器例如1、2 来回答的。我希望在坚持标准库的同时基于不可预测的输入运行 1000 次迭代,因此这两种解决方案都不适合。简单循环(如上所示)在两个限制下效果很好:对于复杂的输入,导致测试失败的原因记录不足(我的真正问题);并且,该方法中的单个故障使整个测试失败。test_<...>

问题

我可以忍受早期的失败,但是我怎样才能在不创建数千行成功输出的情况下获得导致失败的输入呢?

未回答

我尝试了kwargassert...方法msg,但它确实只适用于库已经很好处理的那种琐碎案例。在上面的示例中,unittest 知道显示long导致断言失败的两个 s。我可以用 `self.assertGreater(curr, self.prev, msg="cycle %s" % cycle) 对此进行注释并提供很多关于失败的见解,但是在 assertDictEquals 上显示深度嵌套的字典是一团糟。

理想的解决方案

答案显示了日志记录模块的有趣用途,但每次成功测试都会生成数千行输出。是否可以从测试方法中检测故障?就像是:

    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
4

1 回答 1

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)
于 2012-05-03T04:17:22.837 回答