通常我们写一段临时的python脚本去实现一定的功能,是不会考虑对这段代码进行自动化的测试,因为后续不会对代码进行修改和持续的迭代。然而很多情况下我们编写项目的代码,必须考虑到产品迭代,以及代码修改后原有功能是否依然能正常运行等,这就需要对代码进行测试。
测试的方式很多,包括使用python常用的单元测试框架pytest和unittest等,作为测试驱动开发的工具。除了这些测试框架,python也提供了一种文档型的测试方式,在编写的注释中加入测试用例进行验证,这就是本文的主角,doctest。
注释内嵌脚本
先看一个简单的实例。编写脚本test.py。
def add(a, b): """ 这是段有格式的注释. >>> add(4, 3) 7 >>> add('a', 'b') 'ab' >>> add(0, 6) '7' """ return a + b
脚本定义一个add的函数实现相加,直接返回a和b相加的结果,注释语句才是这段代码精华部分。
‘>>>’开头的行调用函数,并传入测试参数,下一行不带’>>>’,显示的测试预期输出结果,如果函数运行的输出结果与这个结果一致,判断为这条用例执行成功,否则判断执行失败。
doctest在这个脚本中执行的方式有两种。
第一种是在脚本后面加上以下代码:
if __name__=='__main__': import doctest doctest.testmod(verbose=True)
导入doctest模块,并运行testmod函数进行测试。verbose参数为True表示输出详细信息,为False则只存在失败测试用例时才输出信息。
第二种执行doctest的方式是在执行python脚本时以模块的方式运行,运行脚本命令:
python -m doctest test.py
输出效果与第一种方式一致。
拆分代码和注释文件
以上的实例脚本,把测试用例放在了函数的注释里面,如果觉得编写的测试用例过多,会影响代码的阅读性和美观,也可考虑把测试用例单独放在一个文件中,再通过doctest调用待测试脚本执行用例。
上面的实例可拆分为两个文件,第一个是test.py:
def add(a, b): return a + b
第二个文件时case.txt:
单独的注释和用例文件 >>> from test import add >>> add(4, 3) 7 >>> add('a', 'b') 'ab' >>> add(0, 6) '7'
最后执行python命令:
python -m doctest case.txt
doctest会从case.txt执行以’>>>’开始的行的代码,先从test.py文件中导入函数add,然后依次执行三条测试用例,同样能对add函数进行测试。
doctest输出的测试结果如下所示,详细地列出各个测试用例和预期结果,以及实际运行结果与预期结果是否一致。最后一段汇总了测试结果的总体运行情况。但是这个有个不太智能的地方,doctest把所有’>>>’开头的语句都识别为用例,这也包括了导入模块的那条语句,导致结果中识别出4条测试用例,而实际是只有3条。
Trying: from test import add Expecting nothing ok Trying: add(4, 3) Expecting: 7 ok Trying: add('a', 'b') Expecting: 'ab' ok Trying: add(0, 6) Expecting: '7' ********************************************************************** File "case.txt", line 6, in case.txt Failed example: add(0, 6) Expected: '7' Got: 6 ********************************************************************** 1 items had failures: 1 of 4 in case.txt 4 tests in 1 items. 3 passed and 1 failed. ***Test Failed*** 1 failures.
上面的简单实例测试的是一个函数,若测试一个类中的函数,步骤基本一样。比如直接把注释代码写在类中,然后以’>>>’开头实例化类,再调用函数执行测试用例,非常的实用。
最后
各位可以自行尝试一下,会发现在代码注释中写用例也是一件不错的事,以后修改了部分代码,一条命令运行doctest可即刻查看结果是否受到影响,很是方便。