unittest扩展库
infi.unittest的Python项目详细描述
简介
infi.unittest是python标准库提供的标准unittest模块的一组扩展。它比原来的实现提供了一些改进,如下所述。
注意
infi.unittest不支持Python2.6及更低版本,因为在2.7中对unittest模块进行了重大的修改。对不起的。
安装
安装以普通方式进行:
python setup.py install
功能
试验参数
关于unittest最烦人的事情之一是您不能轻松地指定测试参数。如果您有一个测试来测试一个带有参数的api,并且您需要几个案例,每个案例都测试一个特定的值,该值应该有效并且有意义,那么这可能会很烦人,并且会打破干巴巴的原则:
>>> import unittest >>> class MyTest(unittest.TestCase): ... def test__api_call_with_yellow(self): ... self._test_api_call('yellow') ... def test__api_call_with_orange(self): ... self._test_api_call('orange') ... def _test_api_call(self, color): ... some_api(color) # test here... yuck!
使用infi.unittest时,您会得到一种更好的方法:
>>> from infi.unittest import TestCase >>> from infi.unittest import parameters >>> class MyTest(TestCase): ... @parameters.iterate('color', ['orange', 'yellow']) ... def test__api_call(self, color): ... some_api(color) # yay!
上面将为每个可能的值构造一个测试用例,从而为每个值分离用例。也可以使用多个值,将可能性相乘:
>>> class MyTest(TestCase): ... @parameters.iterate('a', [1, 2, 3]) ... @parameters.iterate('b', [4, 5, 6]) ... def test__some_api(self, a, b): ... pass
迭代可以在返回要迭代的序列的函数(或任何可调用对象)上完成:
>>> def get_options(): ... return [1, 2, 3] >>> class MyTest(TestCase): ... @parameters.iterate('a', get_options) ... def test__something(self, a): ... pass对于布尔标志,存在一种在选项之间迭代的更简单的方法:
>>> class MyTest(TestCase): ... @parameters.toggle('a', 'b', 'c') ... def test__something(self, a, b, c): ... pass # will be called with all combinations of True/False for a, b, c
夹具参数
有时您想要编写一组测试,其中用于运行它们的fixture需要在选项上迭代。例如,如果我们想在旧样式类和新样式类上测试实用程序方法:
>>> class OldStyle: ... pass >>> class NewStyle(object): ... pass >>> class TestOldStyle(TestCase): ... def setUp(self): ... super(TestOldStyle, self).setUp() ... self.tested_obj = OldStyle() ... def test__1(self): ... # do something with self.tested_obj ... pass ... def test__2(self): ... # do something with self.tested_obj ... pass >>> class TestNewStyle(TestCase): ... def setUp(self): ... super(TestNewStyle, self).setUp() ... self.tested_obj = NewStyle() ... def test__1(self): ... # do something with self.tested_obj ... pass ... def test__2(self): ... # do something with self.tested_obj ... pass
一个聪明的人,虽然不是很漂亮,但这样做的方式是继承:
>>> class _BaseTest(TestCase): ... def test__1(self): ... # do something with self.tested_obj ... pass ... def test__2(self): ... # do something with self.tested_obj ... pass >>> class OldStyleTest(_BaseTest): ... def setUp(self): ... super(OldStyleTest, self).setUp() ... self.tested_obj = OldStyle() >>> class NewStyleTest(_BaseTest): ... def setUp(self): ... super(NewStyleTest, self).setUp() ... self.tested_obj = NewStyle()
这很糟糕,有些发现方法也会尝试运行basetest(尽管前缀是下划线)。infi.unittest巧妙地解决了这个问题:
>>> class Test(TestCase): ... @parameters.iterate('obj', [NewStyle(), OldStyle()]) ... def setUp(self, obj): ... super(Test, self).setUp() ... self.tested_obj = obj ... def test__1(self): ... # do something with self.tested_obj ... pass ... def test__2(self): ... # do something with self.tested_obj ... pass
unittest甚至可以跨继承进行乘法运算。这意味着下面的代码将最终测试[1,2,3]和[4,5,6]之间的笛卡尔积
>>> class BaseTest(TestCase): ... @parameters.iterate('param', [1, 2, 3]) ... def setUp(self, param): ... super(BaseTest, self).setUp() ... self.base_param = param >>> class DerivedTest(BaseTest): ... @parameters.iterate('param', [4, 5, 6]) ... def setUp(self, param): ... super(DerivedTest, self).param() ... self.derived_param = param ... def test(self): ... self.do_something_with(self.base_param, self.derived_param)
请注意,即使对setup的super()调用也不需要对参数进行处理,它会自动绑定。
抽象基础测试
有时您希望包含一个“基本测试”来促进代码重用。例如在以下情况下:
>>> class FileTestBase(TestCase): ... def test__has_write_method(self): ... self.assertTrue(hasattr(self.file, "write")) ... def test__has_read_method(self): ... self.assertTrue(hasattr(self.file, "read")) >>> class RegularFileTest(FileTestBase): ... def setUp(self): ... super(RegularFileTest, self).setUp() ... self.file = open("somefile", "wb") >>> class SocketFileTest(FileTestBase): ... def setUp(self): ... super(SocketFileTest, self).setUp() ... self.file = connect_to_some_server().makefile()
在这种情况下,一个常规的测试发现机制会着火,因为它会试图运行filetestbase本身,它有一个不完整的设置方案。
infi.unittest为此提供了一个简单的快捷方式。只需标记基类如下:
>>> from infi.unittest import abstract_base_test >>> @abstract_base_test ... class FileTestBase(TestCase): ... pass
基本测试本身也不会直接运行。
注意
nose作为此技术的问题。有一个解决办法,但它涉及到一个鼻子实用功能的实时补丁,所以有可能会打破更新,或根本不工作在某些情况下。在这个问题解决之前(https://github.com/nose-devs/nose/issues/502),鼻梁支撑应该被认为是实验性的。
鼻积分
infi.unittest打破了与优秀的nose:http://code.google.com/p/python nose/>;工具的兼容性,因此它提供了一个nose插件来处理其测试。插件会自动为您启用,因此您不必将–with infi标志传递给nosetests。