我正在使用python unittest模块进行一些测试;但是,这是非常重复的。
我有很多数据要反复运行相同的测试,检查是否正确。但是,我必须为每个人定义一个测试。
例如,我想做类似的事情。我知道我可以使用生成器(在此处的先前线程中找到它)。但是有没有替代品,甚至可能使用不同的测试模块?
任何建议都会很棒。
import unittest
class TestData(unittest.TestCase):
def testNumbers(self):
numbers = [0,11,222,33,44,555,6,77,8,9999]
for i in numbers:
self.assertEqual(i, 33)
答案 0 :(得分:10)
Bill Gribble建议的解决方案示例代码如下所示:
import unittest
class DataTestCase(unittest.TestCase):
def __init__(self, number):
unittest.TestCase.__init__(self, methodName='testOneNumber')
self.number = number
def testOneNumber(self):
self.assertEqual(self.number, 33)
def shortDescription(self):
# We need to distinguish between instances of this test case.
return 'DataTestCase for number %d' % self.number
def get_test_data_suite():
numbers = [0,11,222,33,44,555,6,77,8,9999]
return unittest.TestSuite([DataTestCase(n) for n in numbers])
if __name__ == '__main__':
testRunner = unittest.TextTestRunner()
testRunner.run(get_test_data_suite())
答案 1 :(得分:5)
您可能需要考虑使用unittest.TestSuite类,它将允许您动态构造一组将单独运行的unittest.TestCase实例。您的unittest.TestCase子类应该只定义一个测试方法,该类接受一个构造参数,传入该值以针对该特定实例进行测试。
答案 2 :(得分:4)
ddt
library旨在准确解决您所要求的unittest
[*]。
例如:
import ddt
import unittest
@ddt.ddt
class EvalTests(unittest.TestCase):
@ddt.data(
('1', 1),
('1 == 1', True),
('1 == 2', False),
('1 + 2', 4), ## This will fail
)
def test_eval_expressions(self, case):
expr, exp_value = case
self.assertEqual(eval(expr), exp_value)
当你运行它时,你得到4个TestCase而不是只有一个:
$ python -m unittest -v test_eval.py
test_eval_expressions_1___1___1_ (test_eval.EvalTests) ... ok
test_eval_expressions_2___1__1___True_ (test_eval.EvalTests) ... ok
test_eval_expressions_3___1__2___False_ (test_eval.EvalTests) ... ok
test_eval_expressions_4___1_2___4_ (test_eval.EvalTests) ... FAIL
======================================================================
FAIL: test_eval_expressions_4___1_2___4_ (test_eval.EvalTests)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/usr/lib/python/lib/site-packages/ddt.py", line 129, in wrapper
return func(self, *args, **kwargs)
File "/Work/test_eval.py", line 15, in test_eval_expressions
self.assertEqual(eval(expr), exp_value)
AssertionError: 3 != 4
----------------------------------------------------------------------
Ran 4 tests in 0.002s
FAILED (failures=1)
请注意, ddt 会尝试为生成的TC提供名称。
使用pip安装它:
pip install ddt
[*] pythonic pytest
框架(pytest.mark.parametrize
)的相同解决方案已集成到核心工具中,仅为此功能而值得切换到pytest
。
答案 3 :(得分:2)
在循环中运行断言的问题是,如果其中一个断言失败,则您不知道哪个值导致它(在您的示例中,它会在0
上失败,但您不会知道,直到你调试)。另一方面,重复self.assertEqual(i, 33)
是一个更糟糕的想法,因为它引入了代码重复。
我在测试中所做的是在测试中创建一个简单的,名称很短的内部函数,并使用不同的参数调用它。所以你的功能看起来像这样:
import unittest
class TestData(unittest.TestCase):
def testNumbers(self):
def eq(i):
self.assertEqual(i, 33)
eq(0)
eq(11)
eq(222)
eq(33)
eq(44)
eq(555)
...
这样,当0
的断言失败时,您会立即在unittest
模块打印的堆栈跟踪中看到它。
答案 4 :(得分:2)
在另一篇文章中我偶然发现了 Nose Tests 它更适合数据驱动测试。
class Test_data():
def testNumbers():
numbers = [0,11,222,33,44,555,6,77,8,9999]
for i in numbers:
yield checkNumber, num
def checkNumber(num):
assert num == 33
上面的代码与我的第一篇文章完全相同。 不需要导入,只需编写一个python类。
您可以输入以下命令来执行测试:
nosetests filename
答案 5 :(得分:1)
从Python 3.4开始,您可以使用unittest.TestCase.subTest(msg=None, **params)
上下文管理器(documentation)。这样一来,您只需添加一条语句即可实现所需的功能。
这是您修改为使用subTest()
import unittest
class TestData(unittest.TestCase):
def testNumbers(self):
numbers = [0, 11, 222, 33, 44, 555, 6, 77, 8, 9999]
for i in numbers:
with self.subTest(i=i): # added statement
self.assertEqual(i, 33)
答案 6 :(得分:0)
分拆this回答,这对我来说并不合适。如果我没有处理大量数据量,我确实需要使用不同的输入运行相同的测试。以下测试使用我想要自定义的create_a
和create_b
方法。
要求是使用相同的自定义运行两个测试。
class Tests(unittest.TestCase):
def test_a_uses_b(self):
a = create_a()
b = create_b()
a.b = b
self.assertIs(b.a, a)
def test_b_uses_a(self):
a = create_a()
b = create_b()
b.a = a
self.assertIs(a.b, b)
绕过测试加载器自己实例化TestSuite
和TestCase
会导致错误,因为它需要一个名为runTest
的方法。
结果如下:
class Tests(unittest.TestCase):
def __init__(self, create_a, create_b):
super().__init__()
self.create_b = create_b
self.create_a = create_a
def test_a_uses_b(self):
a = self.create_a()
b = self.create_b()
a.b = b
self.assertIs(b.a, a)
def test_b_uses_a(self):
a = self.create_a()
b = self.create_b()
b.a = a
self.assertIs(a.b, b)
class TestPair1(Tests):
def __init__(self):
super().__init__(create_a1, create_b1)
class TestPair2(Tests):
def __init__(self):
super().__init__(create_a2, create_b2)