我需要为某些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软件包实现这一目标,还是有更好的测试包用于此目的?
答案 0 :(得分:4)
您描述测试的方式通常与单元测试完全匹配。单元测试通常不会从外部文件加载测试数据或休息结果。通常,它只是在单元测试中硬编码。
这并不是说你的计划不会奏效。这只是说这是非典型的。
你有两个选择。
(我们做什么)。编写一个小脚本,执行“为测试用例i加载输入”和“为测试用例i加载预期结果”。使用它来生成所需的unittest代码。 (我们使用Jinja2模板从源文件中编写Python代码。)
然后删除源文件。是的,删除它们。他们只会让你感到困惑。
您剩下的是“典型”表单中的正确Unittest文件,其中包含测试用例的静态数据和预期结果。
编写setUp
方法来执行“为测试用例i加载输入”和“为测试用例i加载预期结果”。写下test
方法来练习UUT。
可能看起来像这样。
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 answer到this question。我再次尝试进行回归测试而不是单元测试,但单元测试框架对两者都有好处。
在我的情况下,我有大约十几个输入文件,涵盖了不同用例的公平传播,我想要在每个用户上调用大约六个测试函数。
我没有编写72个不同的测试,大多数测试与输入参数和结果数据相同,我创建了一个结果字典(键是输入参数,值是测试中每个函数的结果字典)。然后我编写了一个TestCase类来测试6个函数中的每个函数,并通过多次将TestCase添加到测试套件中来复制12个测试文件。