如何在python中生成动态(参数化)单元测试?
时间:2020-03-05 18:44:33 来源:igfitidea点击:
我有某种测试数据,并且想要为每个项目创建一个单元测试。我的第一个想法是这样做:
import unittest l = [["foo", "a", "a",], ["bar", "a", "b"], ["lee", "b", "b"]] class TestSequence(unittest.TestCase): def testsample(self): for name, a,b in l: print "test", name self.assertEqual(a,b) if __name__ == '__main__': unittest.main()
这样做的缺点是它可以在一次测试中处理所有数据。我想即时为每个项目生成一个测试。有什么建议?
解决方案
回答
我用这样的东西:
import unittest l = [["foo", "a", "a",], ["bar", "a", "b"], ["lee", "b", "b"]] class TestSequense(unittest.TestCase): pass def test_generator(a, b): def test(self): self.assertEqual(a,b) return test if __name__ == '__main__': for t in l: test_name = 'test_%s' % t[0] test = test_generator(t[1], t[2]) setattr(TestSequense, test_name, test) unittest.main()
parameterized
软件包可用于自动执行此过程:
from parameterized import parameterized class TestSequence(unittest.TestCase): @parameterized.expand([ ["foo", "a", "a",], ["bar", "a", "b"], ["lee", "b", "b"], ]) def test_sequence(self, name, a, b): self.assertEqual(a,b)
哪个将生成测试:
test_sequence_0_foo (__main__.TestSequence) ... ok test_sequence_1_bar (__main__.TestSequence) ... FAIL test_sequence_2_lee (__main__.TestSequence) ... ok ====================================================================== FAIL: test_sequence_1_bar (__main__.TestSequence) ---------------------------------------------------------------------- Traceback (most recent call last): File "/usr/local/lib/python2.7/site-packages/parameterized/parameterized.py", line 233, in <lambda> standalone_func = lambda *a: func(*(a + p.args), **p.kwargs) File "x.py", line 12, in test_sequence self.assertEqual(a,b) AssertionError: 'a' != 'b'
回答
使用unittest(从3.4开始)
从Python 3.4开始,标准库unittest
软件包具有subTest
上下文管理器。
请参阅文档:
- 26.4.7. 使用子测试区分测试迭代
- 子测试
例子:
from unittest import TestCase param_list = [('a', 'a'), ('a', 'b'), ('b', 'b')] class TestDemonstrateSubtest(TestCase): def test_works_as_expected(self): for p1, p2 in param_list: with self.subTest(): self.assertEqual(p1, p2)
我们还可以为subTest()
指定自定义消息和参数值:
with self.subTest(msg="Checking if p1 equals p2", p1=p1, p2=p2):
用鼻子
鼻子测试框架支持这一点。
示例(下面的代码是包含测试的文件的全部内容):
param_list = [('a', 'a'), ('a', 'b'), ('b', 'b')] def test_generator(): for params in param_list: yield check_em, params[0], params[1] def check_em(a, b): assert a == b
鼻子测试命令的输出:
> nosetests -v testgen.test_generator('a', 'a') ... ok testgen.test_generator('a', 'b') ... FAIL testgen.test_generator('b', 'b') ... ok ====================================================================== FAIL: testgen.test_generator('a', 'b') ---------------------------------------------------------------------- Traceback (most recent call last): File "/usr/lib/python2.5/site-packages/nose-0.10.1-py2.5.egg/nose/case.py", line 203, in runTest self.test(*self.arg) File "testgen.py", line 7, in check_em assert a == b AssertionError ---------------------------------------------------------------------- Ran 3 tests in 0.006s FAILED (failures=1)
回答
我们可以从TestScenarios库中受益。
testscenarios provides clean dependency injection for python unittest style tests. This can be used for interface testing (testing many implementations via a single test suite) or for classic dependency injection (provide tests with dependencies externally to the test code itself, allowing easy testing in different situations).