Pet*_*ann 211 python unit-testing parameterized-unit-test
我有一些测试数据,想为每个项目创建一个单元测试.我的第一个想法是这样做:
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()
Run Code Online (Sandbox Code Playgroud)
这样做的缺点是它在一次测试中处理所有数据.我想在运行中为每个项目生成一个测试.有什么建议?
Dmi*_*hin 153
我使用这样的东西:
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()
Run Code Online (Sandbox Code Playgroud)
该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)
Run Code Online (Sandbox Code Playgroud)
哪个会生成测试:
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'
Run Code Online (Sandbox Code Playgroud)
cod*_*ape 123
使用unittest(自3.4起)
从Python 3.4开始,标准库unittest包就有了subTest上下文管理器.
查看文档:
例:
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)
Run Code Online (Sandbox Code Playgroud)
您还可以指定自定义消息和参数值subTest():
with self.subTest(msg="Checking if p1 equals p2", p1=p1, p2=p2):
Run Code Online (Sandbox Code Playgroud)
用鼻子
示例(下面的代码是包含测试的文件的全部内容):
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
Run Code Online (Sandbox Code Playgroud)
nosetests命令的输出:
> 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)
Run Code Online (Sandbox Code Playgroud)
Guy*_*Guy 69
这可以使用Metaclasses优雅地解决:
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()
Run Code Online (Sandbox Code Playgroud)
Ber*_*ard 44
从Python 3.4开始,为了这个目的,已经将单测试引入了单元测试.有关详细信息,请参阅文档 TestCase.subTest是一个上下文管理器,它允许在测试中隔离断言,以便使用参数信息报告失败但不会停止测试执行.以下是文档中的示例:
class NumbersTest(unittest.TestCase):
def test_even(self):
"""
Test that numbers between 0 and 5 are all even.
"""
for i in range(0, 6):
with self.subTest(i=i):
self.assertEqual(i % 2, 0)
Run Code Online (Sandbox Code Playgroud)
测试运行的输出将是:
======================================================================
FAIL: test_even (__main__.NumbersTest) (i=1)
----------------------------------------------------------------------
Traceback (most recent call last):
File "subtests.py", line 32, in test_even
self.assertEqual(i % 2, 0)
AssertionError: 1 != 0
======================================================================
FAIL: test_even (__main__.NumbersTest) (i=3)
----------------------------------------------------------------------
Traceback (most recent call last):
File "subtests.py", line 32, in test_even
self.assertEqual(i % 2, 0)
AssertionError: 1 != 0
======================================================================
FAIL: test_even (__main__.NumbersTest) (i=5)
----------------------------------------------------------------------
Traceback (most recent call last):
File "subtests.py", line 32, in test_even
self.assertEqual(i % 2, 0)
AssertionError: 1 != 0
Run Code Online (Sandbox Code Playgroud)
这也是unittest2的一部分,因此可用于早期版本的Python.
Jav*_*ier 36
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
Run Code Online (Sandbox Code Playgroud)
该代码将运行load_tests返回的TestSuite中的所有TestCase.发现机制不会自动运行其他测试.
或者,您也可以使用此票证中显示的继承:http://bugs.python.org/msg151444
Ser*_*kiy 29
它可以通过使用pytest来完成.只需test_me.py用内容编写文件:
import pytest
@pytest.mark.parametrize('name, left, right', [['foo', 'a', 'a'],
['bar', 'a', 'b'],
['baz', 'b', 'b']])
def test_me(name, left, right):
assert left == right, name
Run Code Online (Sandbox Code Playgroud)
并使用命令运行测试py.test --tb=short test_me.py.然后输出将如下所示:
=========================== test session starts ============================
platform darwin -- Python 2.7.6 -- py-1.4.23 -- pytest-2.6.1
collected 3 items
test_me.py .F.
================================= FAILURES =================================
_____________________________ test_me[bar-a-b] _____________________________
test_me.py:8: in test_me
assert left == right, name
E AssertionError: bar
==================== 1 failed, 2 passed in 0.01 seconds ====================
Run Code Online (Sandbox Code Playgroud)
很简单!此外pytest具有更多的功能,如fixtures,mark,assert,等...
使用ddt库.它为测试方法添加了简单的装饰器:
import unittest
from ddt import ddt, data
from mycode import larger_than_two
@ddt
class FooTestCase(unittest.TestCase):
@data(3, 4, 12, 23)
def test_larger_than_two(self, value):
self.assertTrue(larger_than_two(value))
@data(1, -3, 2, 0)
def test_not_larger_than_two(self, value):
self.assertFalse(larger_than_two(value))
Run Code Online (Sandbox Code Playgroud)
可以安装此库pip.它不需要nose,并且与标准库unittest模块一起使用非常好.
您将从试用TestScenarios库中受益.
testscenarios为python unittest样式测试提供了干净的依赖注入.这可用于接口测试(通过单个测试套件测试许多实现)或经典依赖注入(在测试代码本身外部提供依赖性测试,允许在不同情况下轻松测试).
parameterized这实际上与之前的答案中提到的相同,但特定于unittest:
def sub_test(param_list):
"""Decorates a test case to run it as a set of subtests."""
def decorator(f):
@functools.wraps(f)
def wrapped(self):
for param in param_list:
with self.subTest(**param):
f(self, **param)
return wrapped
return decorator
Run Code Online (Sandbox Code Playgroud)
用法示例:
class TestStuff(unittest.TestCase):
@sub_test([
dict(arg1='a', arg2='b'),
dict(arg1='x', arg2='y'),
])
def test_stuff(self, arg1, arg2):
...
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
76513 次 |
| 最近记录: |