Python中的单元测试是否有最小的风格?

Kat*_*a B 5 python unit-testing

我想知道人们使用什么技术来简化用于单元测试的代码的"大小".例如,我试图编组一个类的对象并测试元帅的对象(但这假设元帅工作正常).

考虑上课

import unittest
class Nums(object):
    def __init__(self, n1_, n2_, n3_):
        self.n1, self.n2, self.n3 = n1_, n2_, n3_
def marshal(self):
    return "n1 %g, n2 %g, n3 %g"%(self.n1,self.n2,self.n3)
Run Code Online (Sandbox Code Playgroud)

然后是基于编组,基于列表和正常的测试

class NumsTests(unittest.TestCase):
    def setUp(self):
        self.nu = Nums(10,20,30)
    def test_init1(self):
        self.assertEquals(self.nu.marshal(),"n1 %g, n2 %g, n3 %g"%(10,20,30))
    def test_init2(self):
        self.assertEquals([self.nu.n1,self.nu.n2,self.nu.n3],[10,21,31])
    def test_init3(self):
        self.assertEquals(self.nu.n1,10)
        self.assertEquals(self.nu.n2,21)
        self.assertEquals(self.nu.n3,31)
Run Code Online (Sandbox Code Playgroud)

出现以下错误(因为,20!= 21和30!= 31,我的测试初始化​​不好或测试条件错误)

AssertionError: 'n1 10, n2 20, n3 30' != 'n1 10, n2 21, n3 31'

AssertionError: [10, 20, 30] != [10, 21, 31]

AssertionError: 20 != 21
Run Code Online (Sandbox Code Playgroud)

第一个和第二个错误消息很难理解(因为您必须解析字符串或列表).然而,第三种技术在用于测试复杂对象的代码量方面迅速爆炸.

有没有更好的方法来简化单元测试而不会产生困难的错误消息?而且,不依赖于元帅功能的准确性?

[改变test_marshalmarshal]

Owe*_* S. 2

对于测试初始化​​,我建议不要通过调用marshal()函数进行测试。然后,您不仅必须解析出哪个初始化程序失败,还必须弄清楚是您的初始化失败还是编组函数本身失败。我建议的单元测试的“最小风格”是尽可能缩小在任何测试点测试的焦点。

如果我真的必须测试一大堆字段的初始化,我可能会以与 Eli 相同的方式进行重构:

class MyTestCase(unittest.TestCase):
    def assertFieldsEqual(self, obj, expectedFieldValDict):
        for fieldName, fieldVal in expectedFieldValDict.items():
            self.assertFieldEqual(obj, fieldName, fieldVal)
    def assertFieldEqual(self, obj, fieldName, expectedFieldVal):
        actualFieldVal = getattr(obj, fieldName)
        if expectedFieldVal != actualFieldVal:
            msg = "Field %r doesn't match: expected %r, actual %r" % \
                (fieldName, expectedFieldVal, actualFieldVal)
            self.fail(msg)

class NumsTests(MyTestCase):
    def setUp(self):
        self.initFields = {'n1': 10, 'n2': 20, 'n3': 30}
        self.nums = Nums(**initFields)
    def test_init(self):
        self.assertFieldsEqual(self.nums, self.initFields)
Run Code Online (Sandbox Code Playgroud)

“天哪,”我可以听到你说,“代码太多了!” 嗯,是的,但区别是:

  • assertFieldsEqualassertFieldEqual是可重用的函数,已抽象为其他测试用例可以重用的通用测试用例类。
  • 失败消息准确描述了发生的情况。

当需要测试您的元帅功能时,您可以简单地执行以下操作:

def test_marshal(self):
    expected = '...'
    self.assertEqual(expected, self.nums.marshal())
Run Code Online (Sandbox Code Playgroud)

不过,在比较字符串时,我更喜欢一种能够准确告诉我字符串分歧的方法。对于多行字符串,Python 2.7 中现在有一个方法,但我过去为此目的滚动或抄写了自己的方法。