为了账号安全,请及时绑定邮箱和手机立即绑定

Python 单元测试的最佳实践——多个函数适用于同一个对象

Python 单元测试的最佳实践——多个函数适用于同一个对象

慕的地10843 2021-12-08 16:18:27
我有一堆适用于类似对象的函数,例如代表 n 维框的 Numpy 数组:# 3-D box parameterized as:#     box[0] = 3-D min coordinate#     box[1] = 3-D max coordinatebox = np.array([    [1, 3, 0],    [4, 5, 7]])现在我有一大堆要在框列表上运行的函数,例如。volumes, intersection,smallest_containing_box等。在我看来,这是我希望设置的方式:# list of test functions:test_funcs = [volume, intersection, smallest_containing_box, ...]# manually create a bunch of inputs and outputstest_set_1 = (    input = [boxA, boxB, ...], # where each of these are np.Array objects    output = [        [volA, volB, ...], # floats I calculated manually        intersection, # np.Array representing the correct intersection        smallest_containing_box, # etc.    ])# Create a bunch of these, eg. test_set_2, test_set_3, etc. and bundle them in a list:test_sets = [test_set_1, ...]# Now run the set of tests over each of these:test_results = [[assertEqual(test(t.input), t.output) for test in test_funcs] for t in test_sets]我想以这种方式构建它的原因是,我可以创建多组(输入、答案)对,并在每个组上运行所有测试。除非我遗漏了什么,否则unittest这种方法的结构似乎不太好。相反,它似乎希望我为每对函数和输入创建一个单独的 TestCase 对象,即class TestCase1(unittest.TestCase):    def setUp(self):        self.input = [...]        self.volume = [volA, volB, ...]        self.intersection = ...        # etc.    def test_volume(self):        self.assertEqual(volume(self.input), self.volume)    def test_intersection(self):        self.assertEqual(intersection(self.input), self.output)    # etc.# Repeat this for every test case!?这似乎是大量的样板文件。我错过了什么吗?
查看完整描述

2 回答

?
慕无忌1623718

TA贡献1744条经验 获得超4个赞

试试unittest.TestSuite()。这为您提供了一个可以添加测试用例的对象。在您的情况下,创建套件,然后遍历您的列表,创建TestCase所有实例都只有一个测试方法。将测试数据传递给构造函数并将它们保存到那里的属性而不是 in setUp()

当您在调用的方法中创建套件suite()并运行所有套件时,单元测试运行器将检测套件。

注意:为每个TestCase实例分配一个名称或找出哪个失败将非常困难。


查看完整回答
反对 回复 2021-12-08
?
精慕HU

TA贡献1845条经验 获得超8个赞

让met 尝试描述我如何理解您的方法:您已经实现了许多具有相似性的不同函数,即它们对相同类型的输入数据进行操作。在您的测试中,您尝试利用这种相似性:您创建一些输入数据并将该输入数据传递给您的所有函数。

这种以测试数据为中心的方法是不寻常的。典型的单元测试方法是以代码为中心的。原因是,单元测试的一个主要目标是发现代码中的错误。不同的函数有(显然)不同的代码,因此错误的类型可能不同。因此,测试数据通常经过精心设计,以识别相应代码中的某些类型的错误。测试设计方法是有条不紊地设计测试用例的方法,以便在理想情况下可以检测到所有可能的错误。

我怀疑使用以测试数据为中心的方法,您是否会同样成功地找到不同函数中的错误:对于该volume函数,可能存在不适用于intersectionor 的溢出场景(以及下溢场景)smallest_containing_box。相比之下,必须有空交叉点、一点交叉点等。因此,似乎每个功能都可能需要专门设计的测试场景。

关于似乎是以代码为中心的单元测试结果的样板代码:有几种方法可以限制它。同意,您将针对不同的测试功能使用不同的测试方法。但是,您可以使用参数化测试来避免进一步的代码重复。而且,对于您仍然看到为不同功能使用(至少有时)通用测试数据的优势的情况:对于这种情况,您可以使用创建测试数据的工厂函数,并且可以从不同的测试用例中调用. 例如,您可以make-unit-cube在不同的测试中使用一个工厂函数。


查看完整回答
反对 回复 2021-12-08
  • 2 回答
  • 0 关注
  • 233 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信