【问题标题】:Python unittest: respond to failure within the test methodPython unittest:在测试方法内响应失败
【发布时间】:2012-05-03 12:17:22
【问题描述】:

背景

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

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

问题

我可以忍受早期的失败,但是如何在不创建数千行成功输出的情况下获取导致失败的输入?

未回答

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

理想的解决方案

这个answer 展示了日志记录模块的一个有趣用途,但每次成功的测试都会生成数千行输出。是否可以从测试方法中检测故障?比如:

    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

【问题讨论】:

    标签: python unit-testing


    【解决方案1】:
    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)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-10-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-08-21
      • 1970-01-01
      • 2017-10-11
      • 1970-01-01
      相关资源
      最近更新 更多