python函数实验报告的简单介绍( 四 )


TDD的一个关键点是,当我们想添加一个功能时——比如为类添加一个方法—— 我们首次为其编写一个测试用例 。当然,测试将失败 , 因为我们还没有实际编写该方法 。现在,我们编写该方法,一旦方法通过了测试,就可以返回所有测试 , 确保我们新添加的代码没有任何预期外的副作用 。一旦所有测试运行完毕(包括我们为新功能编写的测试),就可以对我们的代码进行检查,并有理有据地相信程序行为符合我们的期望——当然,前提是我们的测试是适当的 。
比如,我们编写了一个函数,该函数在特定的索引位置插入一个字符串,可以像下面这样开始我们的TDD:
def insert_at(string, position, insert):
"""Returns a copy of string with insert inserted at the position
string = "ABCDE"
result =[]
for i in range(-2, len(string) + 2):
... result.append(insert_at(string, i,“-”))
result[:5]
['ABC-DE', 'ABCD-E', '-ABCDE','A-BCDE', 'AB-CDE']
result[5:]
['ABC-DE', 'ABCD-E', 'ABCDE-', 'ABCDE-']
"""
return string
对不返回任何参数的函数或方法(通常返回None),我们通常赋予其由pass构成的一个suite,对那些返回值被试用的 , 我们或者返回一个常数(比如0),或者某个不变的参数——这也是我们这里所做的 。(在更复杂的情况下,返回fake对象可能更有用一一对这样的类,提供mock对象的第三方模块是可用的 。)
运行doctest时会失败,并列出每个预期内的字符串('ABCD-EF'、'ABCDE-F' 等) , 及其实际获取的字符串(所有的都是'ABCD-EF') 。一旦确定doctest是充分的和正确的,就可以编写该函数的主体部分,在本例中只是简单的return string[:position] + insert+string[position:] 。(如果我们编写的是 return string[:position] + insert,之后复制 string [:position]并将其粘贴在末尾以便减少一些输入操作 , 那么doctest会立即提示错误 。)
Python的标准库提供了两个单元测试模块,一个是doctest,这里和前面都简单地提到过,另一个是unittest 。此外,还有一些可用于Python的第三方测试工具 。其中最著名的两个是nose (code.google.com/p/python-nose)与py.test (codespeak.net/py/dist/test/test.html), nose 致力于提供比标准的unittest 模块更广泛的功能,同时保持与该模块的兼容性 , py.test则采用了与unittest有些不同的方法,试图尽可能消除样板测试代码 。这两个第三方模块都支持测试发现,因此没必要写一个总体的测试程序——因为模块将自己搜索测试程序 。这使得测试整个代码树或某一部分 (比如那些已经起作用的模块)变得很容易 。那些对测试严重关切的人,在决定使用哪个测试工具之前,对这两个(以及任何其他有吸引力的)第三方模块进行研究都是值 得的 。
创建doctest是直截了当的:我们在模块中编写测试、函数、类与方法的docstrings 。对于模块,我们简单地在末尾添加了 3行:
if __name__ =="__main__":
import doctest
doctest.testmod()
在程序内部使用doctest也是可能的 。比如,blocks.py程序(其模块在后面)有自己函数的doctest,但以如下代码结尾:
if __name__== "__main__":
main()
这里简单地调用了程序的main()函数,并且没有执行程序的doctest 。要实验程序的 doctest,有两种方法 。一种是导入doctest模块,之后运行程序---比如 , 在控制台中输 入 python3 -m doctest blocks.py (在 Wndows 平台上,使用类似于 C:Python3 lpython.exe 这样的形式替代python3) 。如果所有测试运行良好 , 就没有输出,因此,我们可能宁愿执行python3-m doctest blocks.py-v,因为这会列出每个执行的doctest,并在最后给出结果摘要 。

推荐阅读