5

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

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())
4

1 回答 1

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 关于猴子修补的快速课程):

  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赋值将传递给 NoTraceTestCase 方法addFailureresult对象中的run方法更改为新定义的addFailureSansTraceback函数——该函数首先转换为resulttypes.MethodType.

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

  5. addFailureSansTraceback执行原始版本的addFailure操作——复制两行代码——除了添加一行替换回溯None(使用的赋值err_sans_tb而不是err下一行)。就是这样。

  6. 注意原来addFailure有一个failfast装饰器,所以是导入和使用的。老实说,我没有看过它的作用!

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

于 2012-08-10T23:08:28.630 回答