2013-04-05 59 views
0

我有多个非常相似的类的程序:如何单元测试多个类似的类

class BlackBox1(): 
    def calc(self, a, b): 
     return a + b 

class BlackBox2(): 
    def calc(self, a, b): 
     return a * b 
... 

现在我想要写所有这些类单元测试。当然,我可以为每个Blackbox编写单独的测试。无论如何,因为每个黑盒具有完全相同的方法calc(a, b)进行测试,我在想,如果有像一个“最佳实践”,自动给类和预期结果的抽象测试框架,像

import unittest 
class TestAbstractBox(unittest.TestCase): 
    def setUp(self): 
     self.box = blackbox() 
     self.param_a = a 
     self.param_b = b 
     self.expected_result = result 

    def test_calc_method(self): 
     real_result = self.box.calc(self.param_a, self.param_b) 
     self.assertEqual(real_result, self.expected_result, 
         "{0} gives wrong result".format(self.box.__class__)) 

TAbstractTest = unittest.defaultTestLoader.loadTestsFromTestCase(TestAbstractBox) 

有没有办法将{"blackbox": Blackbox1, "a": 3, "b": 5, "result": 8}{"blackbox": Blackbox2, "a": 4, "b": 7, "result": 28}传递给TestAbstractBox类,使其没有多次相同的代码,但是有一个简单的方法来测试新的Blackboxes?

回答

0

我想我找到了解决办法,基本上遵循this answer

import unittest 

class BlackBox1(): 
    def calc(self, a, b): 
     return a + b 

class BlackBox2(): 
    def calc(self, a, b): 
     return a * b 

class TestBlackBox1(unittest.TestCase): 
    test_params = {"blackbox": BlackBox1, "a": 3, "b": 5, "result": 8} 
    def setUp(self): 
     self.box = self.test_params["blackbox"]() 
     self.param_a = self.test_params["a"] 
     self.param_b = self.test_params["b"] 
     self.expected_result = self.test_params["result"] 

    def test_calc_method(self): 
     real_result = self.box.calc(self.param_a, self.param_b) 
     self.assertEqual(real_result, self.expected_result, 
         "{0} gives wrong result: {1} instead of {2}".format 
         (self.box.__class__, real_result, self.expected_result)) 

class TestBlackBox2(TestBlackBox1): 
    test_params = {"blackbox": BlackBox2, "a": 4, "b": 7, "result": 28} 

TBB1 = unittest.defaultTestLoader.loadTestsFromTestCase(TestBlackBox1) 
TBB2 = unittest.defaultTestLoader.loadTestsFromTestCase(TestBlackBox2) 

无论如何,th为其他答案和其他答案和抱歉没有找到这种方式摆在首位。

+0

如何更好地仅仅在'setUp'中保存一个字符串数组?它只会让你的测试更加复杂。 – freakish 2013-04-05 06:57:02

+0

只需说出最重要的一些:如果需要对一些黑匣子进行额外测试,可以很容易地将它们添加到课程中,如果我有多个测试,那么您的答案每次都需要一个for循环,我只看到第一个在test_calc_method中失败测试(所以如果多个框被破坏,我只能一步一步得到它们)。由于这是一个框架,其他人可以添加更多的黑盒,我可以给他们一个简单的方法来测试他们的盒子。我也喜欢你的榜样,但就我的情况而言,这样做效果更好,看起来更客观。 – 2013-04-05 07:04:48

+0

当然,无论你更适合你。 – freakish 2013-04-05 08:13:57

1

您可以将这些类简单地添加到setUp

class TestAbstractBox(unittest.TestCase): 
    def setUp(self): 
    self.boxes = [Blackbox1(), Blackbox2()] 
    self.param_a = a 
    self.param_b = b 
    self.expected_result = result 

    def test_calc_method(self): 
    for box in self.boxes: 
     real_result = self.box.calc(self.param_a, self.param_b) 
     self.assertEqual(real_result, self.expected_result, 
      "{0} gives wrong result".format(self.box.__class__)) 

编辑版本2:

class TestAbstractBox(unittest.TestCase): 
    def setUp(self): 
    self.boxes = [ 
     { "blackbox":Blackbox1(), "a":a1, "b":b1, "expected_result":result1 }, 
     { "blackbox":Blackbox2(), "a":a2, "b":b2, "expected_result":result2 }, 
    ] 

    def test_calc_method(self): 
    for box in self.boxes: 
     real_result = box["blackbox"].calc(box["a"], box["b"]) 
     self.assertEqual(real_result, box["expected_result"], 
      "{0} gives wrong result".format(box["blackbox"].__class__)) 
+0

但是使用这种方式,我需要有参数和结果的数组,因为我有很多黑匣子,这很快会变得令人困惑。 – 2013-04-05 06:13:33

+0

@SebastianWerk那么你可以保留一个你向我们显示的格式的字典数组:'{“blackbox”:Blackbox1,“a”:3,“b”:5,“result”:8}'。某些时候你仍然需要通过这些参数。 – freakish 2013-04-05 06:16:44

+0

@freakish我在单元测试中吮吸,我正在做很多katas变得更好,这对单元测试来说真的是最好的方法吗?另外,如果他想要进行多于一次的测试,那么即使他只是想测试其他类似'Blackbox()'为'None'的setUp方法,也不允许将两个Blackbox都附加到'self'例?由于'setUp()'为每个测试运行,对吧?顺便说一句,这是一个不批评的问题! :D – 2013-04-05 06:19:42

0

我不认为这是一个很好的方法。

一个测试方法应该只进行一次测试,而不是循环几个assert*调用。否则,如果发生故障,您将无法轻松分辨哪个测试失败。毕竟这是做单位测试的关键。

此外,您不应该冒险通过为新类添加新变体或将现有测试重构为一些常用方法来破坏现有测试。

在几个具有相同方法的类的情况下(考虑在多个派生类中实现通用接口),将接口的公共属性的所有测试放入一个基类并导出个体测试每个课程的测试课程。然后这些派生类将实现合适的setUptearDown方法。他们还可以添加更多特定于被测试类的测试用例。