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

Hou*_*man 5 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'...
Run Code Online (Sandbox Code Playgroud)

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

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())
Run Code Online (Sandbox Code Playgroud)

Gho*_*r21 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)
Run Code Online (Sandbox Code Playgroud)

现在只需将您的测试用例设为 的子类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 方法的对象addFailure中的方法更改为新定义的函数——该函数首先转换为与 .object 兼容的方法。resultrunaddFailureSansTracebackresulttypes.MethodType

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

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

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

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