七、单元测试的改进
Python语言具有一个标准的unittest模块,可以用来编写xUnit风格的测试。您可以重复利用设置/拆卸代码,以适当的方式来组织你的测试,甚至可以运行你的测试。下面是一个用于部分函数add5()的单元测试。TestAdd5类由unittest.TestCase派生而来,并定义了一个setUp()方法,该方法将在执行每个测试方法之前调用。它能确保某些一致状态可以用于所有的测试方法。此测试方法会调用unittest的assertEqual()和assert_()方法。如果任何调用失败,托管的测试方法就会认为出现了一个故障,并转到下一个测试。
from functools import partial
def add(a, b):
return a + b
add5 = partial(add, 5)
class TestAdd5(unittest.TestCase):
def setUp(self):
self.values = range(1, 10)
def test_positive(self):
for v in self.values:
self.assertEquals(add5(v), v + 5)
def test_negative(self):
for v in self.values:
self.assertEquals(add5(-v), 5 - v)
def test_zero(self):
self.assert_(add5(0) == 5)
if __name__ == '__main__':
unittest.main()
在这个例子中,当此模块运行的时候unittest.main()也会运行,并找到所有的测试类(在本例中只有一个),然后运行它们的测试方法并报告运行结果:
...
-------------------------------------------------
Ran 3 tests in 0.000s
OK
Python 3.1能够进行空白测试,并将其标记为“expected to fail.”。空白测试在许多情况下都非常有用。举例来说,有时候为了节约时间而只想运行目前处理的测试,或者在一种平台上运行时想跳过其他平台有关的测试。当在test-first模式下工作的时候,预期的故障是非常有用的。在这个例子中,用于新的功能的测试预期失败,知道修复了代码或者实现了新功能为止。下面是add5的改进版本,它可以操作带有数字的字符串。新版本中添加了一个test_string方法,它从序列中取出所有的值,并将其转化为字符串,然后再将其传递给add5函数:
for v in self.values:
self.assertEquals(add5(str(v)), v + 5)
运行此测试,选择将会产生一个和预期的一样的错误:
..E.
=============================================
ERROR: test_string (__main__.TestAdd5)
---------------------------------------------
Traceback (most recent call last):
File "unittest_test.py", line 26, in test_string
self.assertEquals(add5(str(v)), v + 5)
File "unittest_test.py", line 4, in add
return a + b
TypeError: unsupported operand type(s) for +: 'int' and 'str'
----------------------------------------------------------------
Ran 4 tests in 0.001s
现在,让我们跳过零测试,并允许test_string方法失败:
def test_zero(self):
self.assert_(add5(0) == 5)
@unittest.expectedFailure()
def test_string(self):
for v in self.values:
self.assertEquals(add5(str(v)), v + 5)
现在,此测试成功运行,并报告跳过和预期的故障,如下所示:
..xs
-----------------------------------
Ran 4 tests in 0.001s
OK (skipped=1, expected failures=1)
Unittest模块的另一个新特性是可以使用assertRaises作为上下文管理器:
import no_such_module
在Python 3.0和早先的版本中,您必须在另一函数中包装此代码,并将其传递给assertRaises,如下所示:
import no_such_module
self.assertRaises(ImportError, import_no_such_module)
另外,还增加了许多assertXXX()函数,具体情况请参考有关文档。
八、小结
Python 3.0发布七个月之后,Python核心开发人员于2009年6月27日发布了新的Python 3.1版本。虽然此3.1版本只是对Python 3.0的一次小型升级,但是它不仅为开发者带来许多让人感兴趣的特性,同时在性能方面也有所改善。本文中,我们为读者详细介绍了Python 3.1版本在标准程序库方面的变化,在下一篇中我们将要为读者介绍新版本在性能方面的改进。