我有一些测试数据,想为每个项目创建一个单元测试。我的第一个想法是这样做的:
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
class TestSequence(unittest.TestCase):
def _test_complex_property(self, a, b):
self.assertEqual(a,b)
def test_foo(self):
self._test_complex_property("a", "a")
def test_bar(self):
self._test_complex_property("a", "b")
def test_lee(self):
self._test_complex_property("b", "b")
if __name__ == '__main__':
unittest.main()
既然我们不应该重复,我的第二个建议建立在Javier的回答之上:接受基于属性的测试。假设库:
“在生成测试用例方面比我们人类更加无情地迂回”
会提供简单的计数例子吗
与任何测试运行程序一起工作
具有更多有趣的特性(统计数据、额外的测试输出……)
类TestSequence (unittest.TestCase):
st.text @given (st.text () ()
Def test_complex_property(self, a, b):
self.assertEqual (a, b)
为了测试您的特定示例,只需添加:
@example("a", "a")
@example("a", "b")
@example("b", "b")
为了只运行一个特定的示例,您可以注释掉其他示例(提供的示例将首先运行)。你可能想要使用@given(st.nothing())。另一种选择是将整个区块替换为:
@given(st.just("a"), st.just("b"))
好的,您没有不同的测试名称。但也许你只需要:
被测属性的描述性名称。
哪个输入会导致失败(伪造的例子)。
有趣的例子
元编程很有趣,但它也会碍事。这里的大多数解决方案都很难:
有选择地启动测试
指向给出测试名称的代码
所以,我的第一个建议是遵循简单/显式路径(适用于任何测试运行程序):
import unittest
class TestSequence(unittest.TestCase):
def _test_complex_property(self, a, b):
self.assertEqual(a,b)
def test_foo(self):
self._test_complex_property("a", "a")
def test_bar(self):
self._test_complex_property("a", "b")
def test_lee(self):
self._test_complex_property("b", "b")
if __name__ == '__main__':
unittest.main()
既然我们不应该重复,我的第二个建议建立在Javier的回答之上:接受基于属性的测试。假设库:
“在生成测试用例方面比我们人类更加无情地迂回”
会提供简单的计数例子吗
与任何测试运行程序一起工作
具有更多有趣的特性(统计数据、额外的测试输出……)
类TestSequence (unittest.TestCase):
st.text @given (st.text () ()
Def test_complex_property(self, a, b):
self.assertEqual (a, b)
为了测试您的特定示例,只需添加:
@example("a", "a")
@example("a", "b")
@example("b", "b")
为了只运行一个特定的示例,您可以注释掉其他示例(提供的示例将首先运行)。你可能想要使用@given(st.nothing())。另一种选择是将整个区块替换为:
@given(st.just("a"), st.just("b"))
好的,您没有不同的测试名称。但也许你只需要:
被测属性的描述性名称。
哪个输入会导致失败(伪造的例子)。
有趣的例子
这可以使用元类优雅地解决:
import unittest
l = [["foo", "a", "a",], ["bar", "a", "b"], ["lee", "b", "b"]]
class TestSequenceMeta(type):
def __new__(mcs, name, bases, dict):
def gen_test(a, b):
def test(self):
self.assertEqual(a, b)
return test
for tname, a, b in l:
test_name = "test_%s" % tname
dict[test_name] = gen_test(a,b)
return type.__new__(mcs, name, bases, dict)
class TestSequence(unittest.TestCase):
__metaclass__ = TestSequenceMeta
if __name__ == '__main__':
unittest.main()
我有麻烦使这些工作为setUpClass。
下面是Javier回答的一个版本,它允许setUpClass访问动态分配的属性。
import unittest
class GeneralTestCase(unittest.TestCase):
@classmethod
def setUpClass(cls):
print ''
print cls.p1
print cls.p2
def runTest1(self):
self.assertTrue((self.p2 - self.p1) == 1)
def runTest2(self):
self.assertFalse((self.p2 - self.p1) == 2)
def load_tests(loader, tests, pattern):
test_cases = unittest.TestSuite()
for p1, p2 in [(1, 2), (3, 4)]:
clsname = 'TestCase_{}_{}'.format(p1, p2)
dct = {
'p1': p1,
'p2': p2,
}
cls = type(clsname, (GeneralTestCase,), dct)
test_cases.addTest(cls('runTest1'))
test_cases.addTest(cls('runTest2'))
return test_cases
输出
1
2
..
3
4
..
----------------------------------------------------------------------
Ran 4 tests in 0.000s
OK