saf*_*fsd 15 python unit-testing
我正在为一系列函数实现单元测试,这些函数都共享多个不变量.例如,调用具有两个矩阵的函数产生已知形状的矩阵.
我想编写单元测试来测试该属性的整个函数系列,而不必为每个函数编写单独的测试用例(特别是因为稍后可能会添加更多函数).
一种方法是迭代这些函数的列表:
import unittest
import numpy
from somewhere import the_functions
from somewhere.else import TheClass
class Test_the_functions(unittest.TestCase):
def setUp(self):
self.matrix1 = numpy.ones((5,10))
self.matrix2 = numpy.identity(5)
def testOutputShape(unittest.TestCase):
"""Output of functions be of a certain shape"""
for function in all_functions:
output = function(self.matrix1, self.matrix2)
fail_message = "%s produces output of the wrong shape" % str(function)
self.assertEqual(self.matrix1.shape, output.shape, fail_message)
if __name__ == "__main__":
unittest.main()
Run Code Online (Sandbox Code Playgroud)
我从Dive Into Python中得到了这个想法.在那里,它不是正在测试的函数列表,而是已知输入 - 输出对的列表.这种方法的问题在于,如果列表中的任何元素未通过测试,则后面的元素不会被测试.
我查看了子类化unittest.TestCase并以某种方式提供了作为参数测试的特定函数,但据我所知,这阻止我们使用unittest.main(),因为没有办法将参数传递给测试用例.
我还看了动态地将"testSomething"函数附加到测试用例,使用带有lamdba的setattr,但是测试用例没有识别它们.
我怎样才能重写这个,所以扩展测试列表仍然是微不足道的,同时仍然确保每个测试都运行?
S.L*_*ott 11
这是我最喜欢的"相关测试系列"的方法.我喜欢表达常见功能的TestCase的显式子类.
class MyTestF1( unittest.TestCase ):
theFunction= staticmethod( f1 )
def setUp(self):
self.matrix1 = numpy.ones((5,10))
self.matrix2 = numpy.identity(5)
def testOutputShape( self ):
"""Output of functions be of a certain shape"""
output = self.theFunction(self.matrix1, self.matrix2)
fail_message = "%s produces output of the wrong shape" % (self.theFunction.__name__,)
self.assertEqual(self.matrix1.shape, output.shape, fail_message)
class TestF2( MyTestF1 ):
"""Includes ALL of TestF1 tests, plus a new test."""
theFunction= staticmethod( f2 )
def testUniqueFeature( self ):
# blah blah blah
pass
class TestF3( MyTestF1 ):
"""Includes ALL of TestF1 tests with no additional code."""
theFunction= staticmethod( f3 )
Run Code Online (Sandbox Code Playgroud)
添加一个函数,添加一个子类MyTestF1.MyTestF1的每个子类都包含MyTestF1中的所有测试,没有任何重复的代码.
独特的功能以明显的方式处理.新方法被添加到子类中.
它完全兼容 unittest.main()
您不必在此处使用Meta Classes.一个简单的循环就可以了.看看下面的例子:
import unittest
class TestCase1(unittest.TestCase):
def check_something(self, param1):
self.assertTrue(param1)
def _add_test(name, param1):
def test_method(self):
self.check_something(param1)
setattr(TestCase1, 'test_'+name, test_method)
test_method.__name__ = 'test_'+name
for i in range(0, 3):
_add_test(str(i), False)
Run Code Online (Sandbox Code Playgroud)
执行for后,TestCase1有3种测试方法,由nose和unittest支持.
您可以使用元类动态插入测试。这对我来说很好用:
import unittest
class UnderTest(object):
def f1(self, i):
return i + 1
def f2(self, i):
return i + 2
class TestMeta(type):
def __new__(cls, name, bases, attrs):
funcs = [t for t in dir(UnderTest) if t[0] == 'f']
def doTest(t):
def f(slf):
ut=UnderTest()
getattr(ut, t)(3)
return f
for f in funcs:
attrs['test_gen_' + f] = doTest(f)
return type.__new__(cls, name, bases, attrs)
class T(unittest.TestCase):
__metaclass__ = TestMeta
def testOne(self):
self.assertTrue(True)
if __name__ == '__main__':
unittest.main()
Run Code Online (Sandbox Code Playgroud)
如果你已经使用了鼻子(并且你的一些评论暗示你是),为什么不使用测试生成器,这是实现参数测试最直接的方法我遇到过:
例如:
from binary_search import search1 as search
def test_binary_search():
data = (
(-1, 3, []),
(-1, 3, [1]),
(0, 1, [1]),
(0, 1, [1, 3, 5]),
(1, 3, [1, 3, 5]),
(2, 5, [1, 3, 5]),
(-1, 0, [1, 3, 5]),
(-1, 2, [1, 3, 5]),
(-1, 4, [1, 3, 5]),
(-1, 6, [1, 3, 5]),
(0, 1, [1, 3, 5, 7]),
(1, 3, [1, 3, 5, 7]),
(2, 5, [1, 3, 5, 7]),
(3, 7, [1, 3, 5, 7]),
(-1, 0, [1, 3, 5, 7]),
(-1, 2, [1, 3, 5, 7]),
(-1, 4, [1, 3, 5, 7]),
(-1, 6, [1, 3, 5, 7]),
(-1, 8, [1, 3, 5, 7]),
)
for result, n, ns in data:
yield check_binary_search, result, n, ns
def check_binary_search(expected, n, ns):
actual = search(n, ns)
assert expected == actual
Run Code Online (Sandbox Code Playgroud)
生产:
$ nosetests -d
...................
----------------------------------------------------------------------
Ran 19 tests in 0.009s
OK
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
5798 次 |
| 最近记录: |