我有一些测试数据,想为每个项目创建一个单元测试。我的第一个想法是这样做的:
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()
这样做的缺点是它在一个测试中处理所有数据。我想在飞行中为每个项目生成一个测试。有什么建议吗?
您可以使用TestSuite和自定义TestCase类。
import unittest
class CustomTest(unittest.TestCase):
def __init__(self, name, a, b):
super().__init__()
self.name = name
self.a = a
self.b = b
def runTest(self):
print("test", self.name)
self.assertEqual(self.a, self.b)
if __name__ == '__main__':
suite = unittest.TestSuite()
suite.addTest(CustomTest("Foo", 1337, 1337))
suite.addTest(CustomTest("Bar", 0xDEAD, 0xC0DE))
unittest.TextTestRunner().run(suite)
load_tests是2.7中引入的一种鲜为人知的机制,用于动态创建TestSuite。有了它,您可以轻松地创建参数化测试。
例如:
import unittest
class GeneralTestCase(unittest.TestCase):
def __init__(self, methodName, param1=None, param2=None):
super(GeneralTestCase, self).__init__(methodName)
self.param1 = param1
self.param2 = param2
def runTest(self):
pass # Test that depends on param 1 and 2.
def load_tests(loader, tests, pattern):
test_cases = unittest.TestSuite()
for p1, p2 in [(1, 2), (3, 4)]:
test_cases.addTest(GeneralTestCase('runTest', p1, p2))
return test_cases
该代码将运行load_tests返回的测试套件中的所有测试用例。发现机制不会自动运行其他测试。
或者,您也可以使用此票据所示的继承:http://bugs.python.org/msg151444
我发现这很适合我的目的,特别是当我需要生成在数据集合上执行稍微不同的过程的测试时。
import unittest
def rename(newName):
def renamingFunc(func):
func.__name__ == newName
return func
return renamingFunc
class TestGenerator(unittest.TestCase):
TEST_DATA = {}
@classmethod
def generateTests(cls):
for dataName, dataValue in TestGenerator.TEST_DATA:
for func in cls.getTests(dataName, dataValue):
setattr(cls, "test_{:s}_{:s}".format(func.__name__, dataName), func)
@classmethod
def getTests(cls):
raise(NotImplementedError("This must be implemented"))
class TestCluster(TestGenerator):
TEST_CASES = []
@staticmethod
def getTests(dataName, dataValue):
def makeTest(case):
@rename("{:s}".format(case["name"]))
def test(self):
# Do things with self, case, data
pass
return test
return [makeTest(c) for c in TestCluster.TEST_CASES]
TestCluster.generateTests()
TestGenerator类可以用来生成不同的测试用例集,比如TestCluster。
TestCluster可以被认为是TestGenerator接口的实现。
你可以使用nose-ittr插件(pip install nose-ittr)。
它非常容易与现有的测试集成,并且只需要极小的更改(如果有的话)。它还支持nose多处理插件。
注意,您还可以为每个测试定制一个设置函数。
@ittr(number=[1, 2, 3, 4])
def test_even(self):
assert_equal(self.number % 2, 0)
它也可以像内置插件attrib一样传递nosetest参数。通过这种方式,你可以只运行特定参数的特定测试:
nosetest -a number=2
只使用元类,如这里所示;
class DocTestMeta(type):
"""
Test functions are generated in metaclass due to the way some
test loaders work. For example, setupClass() won't get called
unless there are other existing test methods, and will also
prevent unit test loader logic being called before the test
methods have been defined.
"""
def __init__(self, name, bases, attrs):
super(DocTestMeta, self).__init__(name, bases, attrs)
def __new__(cls, name, bases, attrs):
def func(self):
"""Inner test method goes here"""
self.assertTrue(1)
func.__name__ = 'test_sample'
attrs[func.__name__] = func
return super(DocTestMeta, cls).__new__(cls, name, bases, attrs)
class ExampleTestCase(TestCase):
"""Our example test case, with no methods defined"""
__metaclass__ = DocTestMeta
输出:
test_sample (ExampleTestCase) ... OK