【问题标题】:Python Unittest Modularity vs ReadabilityPython Unittest 模块化与可读性
【发布时间】:2012-02-14 04:58:16
【问题描述】:

我有一个 Python 单元测试,其中一些测试测试了相同类型的对象。一个测试类的基本大纲是:

class TestClass(unittest.TestCase):
    def setup(self):
        ...

    def checkObjects(self, obj):
        for i in [...values...]:
            self.assertEqual(starttags(i,obj), endtags(i,obj))

    def testOne(self):
        #Get object one.
        checkObjects(objone)

    def testAnother(self):
        #Access another object.
        checkObjects(another)

    ... various tests for similar objects.

虽然它是模块化的,但我注意到任何失败都会产生类似 AssertionError: number != anothernumber 之类的错误,以及生成错误的代码行self.assertEqual(starttags(i,obj), endtags(i,obj))。如果我列出了测试而不是放在 for 循环中,我会有类似的东西:

self.assertEqual(starttags(value1,obj), endtags(value1,obj))
self.assertEqual(starttags(value2,obj), endtags(value2,obj))

它准确显示了哪种情况导致了错误,但是是复制粘贴代码,我认为通常不推荐这样做。我最近注意到了这个问题,当一名贡献者重新设计了一个更clean 的单元测试时,不幸的是,它几乎不会提供关于断言失败的调试信息。那么,在这些情况下,最佳实践是什么?像元组列表这样的东西,用 assertEquals 送入 for 循环是“更干净”的,但是在不同的行上复制粘贴不同的值会提供有用的堆栈跟踪。

【问题讨论】:

  • 解决此问题的一种方法是将错误消息添加到 self.assertEqual 调用。说:self.assertEqual(starttags(i,obj), endtags(i,obj), message) 其中 message 是一个详细的字符串,其中包含 object 的字符串表示形式、测试失败的 i 的值等。
  • 这似乎是这个问题的答案

标签: python unit-testing assert


【解决方案1】:

如果cleaner 是指更少的代码,那么这种cleaner 代码并不总是更多可读 代码。事实上,它通常可读性较差(尤其是当你回到它时)。您总是可以进行花哨的重构,但您需要知道何时停止。从长远来看,使用更明显、更简单的代码总是比试图压缩少一行代码来获得人为的收益更好——不仅仅是在单元测试方面。

单元测试有自己的规则。例如,它们通常允许与您的常规代码标准所说的不同的命名约定,您几乎不会记录它 - 它们是您代码库的一种特殊部分。此外,重复代码并不少见。实际上,进行许多外观相似的小型测试是很常见的。

设计您的测试(代码)时要考虑到简单性

目前,即使在编写测试阶段,您的测试也令人困惑 - 想象一下在 3 个月后回到该代码。想象一下,由于其他人其他地方做了一些改变,其中一个测试中断了。不会好转的。

以这样一种方式设计您的测试,即当其中一个发生故障时,您立即知道它为什么这样做以及在哪里发生。不仅如此 - 以这样的方式设计它们,你可以在眨眼之间知道它们在做什么。在测试代​​码中使用 for 循环ifs 以及基本上任何其他类型的控制流 机制(或过于广泛的重构),通常会导致一个问题突然出现在您的脑海中 - 我们在这里做什么?这是您不想自己问的问题。

用比我聪明的人的话来总结这篇冗长的帖子:

任何傻瓜都可以编写计算机可以理解的代码。优秀的程序员编写人类可以理解的代码。

-Martin Fowler 等人,Refactoring: Improving the Design of Existing Code, 1999

帮自己一个忙,遵守这条规则。

【讨论】:

    【解决方案2】:

    使用鼻子测试,它使您的测试更加清晰:

    #!/usr/bin/python
    def test_one():
        for i in [...]:
            assert xxx(i) == yyy
    
    def test_two():
        ...
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-10-16
      • 2020-11-26
      • 2014-01-26
      • 2013-12-25
      • 1970-01-01
      • 1970-01-01
      • 2017-10-12
      相关资源
      最近更新 更多