如何编写单元测试,其中每个测试用例具有不同的输入但是相同?

时间:2010-02-03 23:44:39

标签: python unit-testing

我需要为某些python类创建一个单元测试。我有一个输入和预期结果的数据库,应由UUT为这些输入生成。

以下是我想要做的伪代码:

for i=1 to NUM_TEST_CASES:
    Load input for test case i
    execute UUT on the input and save output of run
    Load expected result for test case i
    Compare output of run with the expected result

我可以使用unittest软件包实现这一目标,还是有更好的测试包用于此目的?

5 个答案:

答案 0 :(得分:4)

您描述测试的方式通常与单元测试完全匹配。单元测试通常不会从外部文件加载测试数据或休息结果。通常,它只是在单元测试中硬编码。

这并不是说你的计划不会奏效。这只是说这是非典型的。

你有两个选择。

  1. (我们做什么)。编写一个小脚本,执行“为测试用例i加载输入”和“为测试用例i加载预期结果”。使用它来生成所需的unittest代码。 (我们使用Jinja2模板从源文件中编写Python代码。)

    然后删除源文件。是的,删除它们。他们只会让你感到困惑。

    您剩下的是“典型”表单中的正确Unittest文件,其中包含测试用例的静态数据和预期结果。

  2. 编写setUp方法来执行“为测试用例i加载输入”和“为测试用例i加载预期结果”。写下test方法来练习UUT。

  3. 可能看起来像这样。

    class OurTest( unittest.TestCase ):
        def setUp( self ):
            self.load_data()
            self.load_results()
            self.uut = ... UUT ...
        def runTest( self ):
            ... exercise UUT with source data ...
            ... check results, using self.assertXXX methods ...
    

    想要多次运行?这样做的一种方式。

    class Test1( OurTest ):
        source_file = 'this'
        result_file = 'that'
    
    class Test2( OutTest ):
        source_file= 'foo'
        result_file= 'bar'
    

    这将允许unittest主程序查找并运行您的测试。

答案 1 :(得分:3)

我们做这样的事情是为了在unittest框架内运行实际上集成(回归)测试(实际上是内部定制,这给我们带来了巨大的好处,例如:在一组机器等上并行运行测试 - 这种定制的巨大附加值是我们如此热衷于使用unittest框架的原因。

每个测试都在一个文件中表示(在该测试中使用的参数,然后是预期的结果)。我们的integration_test从目录中读取所有这些文件,解析每个文件,然后调用:

def addtestmethod(testcase, uut, testname, parameters, expresults):
  def testmethod(self):
    results = uut(parameters)
    self.assertEqual(expresults, results)
  testmethod.__name__ = testname
  setattr(testcase, testname, testmethod)

我们从一个空的测试用例类开始:

class IntegrationTest(unittest.TestCase): pass

然后在循环中调用addtestmethod(IntegrationTest, ...,我们正在读取所有相关文件并解析它们以获取testname,参数和表达式。

最后,我们称我们的内部专业测试运行器负责繁重(在集群中的可用机器上分发测试,收集结果等)。我们不想重新发明那些增值丰富的轮子,所以我们正在制作一个测试案例,接近一个典型的“手工编码”测试用例,以“欺骗”测试跑步者为我们工作; )。

除非您有特定的理由(优秀的测试跑步者等)使用unittest的方法进行(整合?)测试,否则您可能会发现使用不同的方法可以简化您的生活。然而,这个是非常可行的,我们对它的结果非常满意(其中大部分包括快速运行的大型集成/回归测试套件! - )。

答案 2 :(得分:1)

对我而言,pytest似乎只有您需要的东西。

您可以parametrise tests以便相同的测试运行的次数与您输入的次数相同,所需的只是一个装饰器(没有循环等)。

这是一个简单的例子:

import pytest
@pytest.mark.parametrize("test_input,expected", [
    ("3+5", 8),
    ("2+4", 6),
    ("6*9", 42),
])
def test_eval(test_input, expected):
    assert eval(test_input) == expected

这里参数化有两个参数 - 参数名称为字符串,这些参数的值为可迭代。

然后将为列表的每个元素调用

test_eval一次。

答案 3 :(得分:0)

也许您可以使用doctest。了解输入和输出(并能够将案例编号映射到函数名称),您应该能够生成如下文本文件:

>>> from XXX import function_name1
>>> function_name1(input1)
output1
>>> from XXX import function_name2
>>> function_name2(input2)
output2
...

然后只使用doctest.testfile('cases.txt')。值得一试。

答案 4 :(得分:0)

您可能还想查看my answerthis question。我再次尝试进行回归测试而不是单元测试,但单元测试框架对两者都有好处。

在我的情况下,我有大约十几个输入文件,涵盖了不同用例的公平传播,我想要在每个用户上调用大约六个测试函数。

我没有编写72个不同的测试,大多数测试与输入参数和结果数据相同,我创建了一个结果字典(键是输入参数,值是测试中每个函数的结果字典)。然后我编写了一个TestCase类来测试6个函数中的每个函数,并通过多次将TestCase添加到测试套件中来复制12个测试文件。