Django:如何在单元测试中隐藏Traceback以提高可读性?

时间:2012-08-10 20:26:17

标签: django unit-testing

我发现在一个简单的失败的单元测试中获得如此多的细节有点恼人。是否可以抑制除了实际定义的断言消息之外的所有内容?

Creating test database for alias 'default'...
.F
======================================================================
FAIL: test_get_sales_item_for_company (my_app.tests.SalesItemModelTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/kave/projects/my/my_app/tests.py", line 61, in test_get_sales_item_for_company
    self.assertEqual(sales_items.count(), 1, 'Expected one sales item for this company, but got %s' % sales_items.count())
AssertionError: Expected one sales item for this company, but got 2

----------------------------------------------------------------------
Ran 2 tests in 0.313s

FAILED (failures=1)
Destroying test database for alias 'default'...

我觉得这不必要了。我需要知道失败的测试名称(方法)和断言消息。真的不需要追溯..

Traceback (most recent call last):
  File "/home/kave/projects/my/my_app/tests.py", line 61, in test_get_sales_item_for_company
    self.assertEqual(sales_items.count(), 1, 'Expected one sales item for this company, but got %s' % sales_items.count())

1 个答案:

答案 0 :(得分:1)

猴子修补救援。你可以通过继承Django的TestCase来解决失败的追溯问题,而无需触及你的Django安装,如下所示:

import types
from django.utils.unittest.result import failfast
from django.test import TestCase

@failfast
def addFailureSansTraceback(self, test, err):
    err_sans_tb = (err[0], err[1], None)
    self.failures.append((test, self._exc_info_to_string(err_sans_tb, test)))
    self._mirrorOutput = True

class NoTraceTestCase(TestCase):
    def run(self, result=None):
        result.addFailure = types.MethodType(addFailureSansTraceback, result)
        super(NoTraceTestCase, self).run(result)

现在只需将您的测试用例设为NoTraceTestCase而不是TestCase的子类,您就可以了。不再追溯失败。 (注意异常仍然会打印回溯。如果你愿意的话,你可以将这些异常修补。)

以下是它的工作原理(感谢Jason Pratt for the quick lesson on monkey patching):

  1. Django的测试运行器为每次测试运行调用TestCase的run方法。 result参数是django.utils.unittest.result.TestResult类的一个实例,它处理向用户显示测试结果。每当测试失败时,run都会拨打以下电话:result.addFailure(self, sys.exc_info())。这就是回溯的来源 - 作为sys.exc_info()返回的元组中的第三项。

  2. 现在,只需使用原始代码的副本覆盖run并根据需要进行调整即可。但是run方法是一个很好的75行长,所有需要改变的是一行,并且无论如何为什么错过了使用猴子修补的乐趣的机会?

  3. result.addFailure赋值将addFailure对象中传递给NoTraceTestCase的result方法的run方法更改为新定义的addFailureSansTraceback函数 - 首先使用result转换为与types.MethodType - 对象兼容的方法。

  4. super调用调用Django现有的TestCase run。现在,当现有代码运行时,对addFailure的调用实际上会调用新版本,即addFailureSansTraceback

  5. addFailureSansTraceback执行addFailure的原始版本所做的事情 - 复制两行代码 - 除了添加一行用None替换回溯(分配)到下一行代替err_sans_tb的{​​{1}}。就是这样。

  6. 请注意,原始err有一个addFailure装饰器,因此会导入并使用它。说实话,我还没看过它的作用!

  7. 免责声明:我没有彻底研究过Django的测试代码。这只是一个快速的补丁,让它在常见的情况下工作。使用风险自负!