unittest:一个通用的测试框架
doctest:一个更简单的模块,是为检查文档而设计的,同时非常适合用来编写单元测试。
1.doctest
交互式会话是一种很有用的文档,可将其放在文档字符串中。
例如:编写一个计算平方的函数,并在其文档字符串中添加一个示例;
def square(x): ... 计算平方并返回结果 >>>square(2) 4 >>>aquare(3) 9 ... return x*x
如上,在文档字符串中添加了一些文字,假设函数square是在模块my_math中定义,就可在模块末尾添加如下代码:
if name =='_main_' import doctest,my_math doctest.testmod(my_math)
添加的代码不多,只是导入模块doctest 和模块my_math本身,再运行模块doctest中的函数testmod(表示对模块进行测试)
$python my_math.py
$
看起来什么都没发生,但是这是好事。函数doctest.testmod读取模块中的所有文档字符串,查找看起来像是从交互式解释器中摘取的示例,再检查这些示例是否反映了实际情况。
注意;如果这里编写的是真实函数,应该根据前面指定的规则先编写文档字符串,再使用doctest运行脚本看看测试是否会失败,染添加刚好让测试得以通过的代码,接下来确保实现是正确的。
为了获得更多的输出,可在运行脚本时指定开关-v(verbose,意为详尽)
$python my_math.py -v
生成如下输出:
Running my_math._doc_ 0 of 0 examples failed in my_math._doc_ Running my_math.square._doc_ Trying:square(2) Expecting:4 ok Trying:square(3) Expecting:9 ok 0 of 2 examples failed in my_math.square._doc_ 1 items had no tests: test 1 items passed all tests: 2 tests in my_math.square 2 tests in 2 items. 2 passed and 0 failed. Test passed
函数testmod检查模块的文档字符串和函数的文档字符串。
有测试数据,就可以放心修改代码了。
Failure in example:square(3) from line #s of my_math.square Expected:9 Got:27 1items had failures: 1 of 2 in my_math.square ***Test Failed*** 1 failures
捕捉到了bug,并清楚地指出错误出什么什么地方,就可以修复这个错误了
注意:不要盲目的信任测试,而且务必要测试足够多的情形。例如square(2)的测试没有捕捉到bug,因为x == 2时, x ** 2 和 x ** x 等价
2.unittest
虽然doctest使用起来很容易,但unittest(基于流行的java测试框架unit)更灵活、更强大;unittest的学习门槛比较高,但是它可以以结构化方式编写庞大而详尽的测试集
注意:标准库包含另外两个有趣的单元测试工具:pytest(pytest.org)和nose(nose.readthed ocs.io)
案例:需要编写一个名为 my_math的模块,其中包含一个计算乘积的函数product。
首先先使用模块unittest中的TestCase类编写一个测试(存储在文件test_y_math.py中)
import unittest,my_math class ProductTestCase(unittest.TestCase): def test_intergers(self): for x in range(-10,10): for y in range(-10,10): p = my_math.product(x,y) self.assertEqual(p,x*y, 'Integer multiplication faied') def test_floats(self): for x in range(-10,10): for y in range(-10,10): x = x / 10 y = y / 10 p = my_math.product(x,y) self.assertEqual(p, x*y, 'Float multiolication failed') if __name__=='_main_':unittest.main()
函数unittest.main负责替你运行测试:实例化所有的TestCase子类,并运行所有名称以test开头的方法。
注意:如果你定义了方法setup和teardown,它们将分别在每个测试方法之前和之后执行。可以使用这些方法执行适用于所有测试的初始化代码和清理代码,这些代码称为 测试夹具(test fixture)
当然,运行这个测试脚本将引发异常,指出模块my_math不存在。诸如assertEqual等方法检查指定的条件,以判断指定的测试是成功还是失败。TestCase类嗨包含很多与之类似的方法,例如assertTrue、assertIsNone 和 assertAlmostEqual.
模块unittest区分错误和失败。错误指的是引发了异常,而失败是调用failUnless等方法的结果
可下来就需要编写框架代码,消除错误,只留下失败。
待补充~