python函数性能测试的简单介绍

后端编程Python3-调试、测试和性能剖析(下)单元测试(Unit Testing)
为程序编写测试——如果做的到位——有助于减少bug的出现 , 并可以提高我们对程序按预期目标运行的信心 。通常 , 测试并不能保证正确性,因为对大多数程序而言 ,  可能的输入范围以及可能的计算范围是如此之大,只有其中最小的一部分能被实际地进 行测试 。尽管如此,通过仔细地选择测试的方法和目标,可以提高代码的质量 。
大量不同类型的测试都可以进行,比如可用性测试、功能测试以及整合测试等 。这里, 我们只讲单元测试一对单独的函数、类与方法进行测试,确保其符合预期的行为 。
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行:

推荐阅读