python测试

测试的目的,也就是用来证明错误的存在,而不是证明程序有没有错误。即使最简单的程序,也有无数种输入的可能,就像下面一样:

def isBigger(x,y):
'''
x和y是证书,如果x<y则返回True,否则返回False
'''

毫不夸张地说,使用所有整数对运行这个程序会非常枯燥乏味。最好的方式是,只使用一些特殊的整数对来运行程序,如果程序中有错误,那么这些整数对就应该极有可能产生错误答案。 测试的关键就是找到这样一组输入,可以称之为测试套件。它有很大可能发现程序错误,又 不需要程序运行太长时间。找到这样的输入的关键是,对所有可能的输入空间进行分区,将其划 分为对程序正确性提供相同信息的多个子集,然后构建测试套件,使其包含来自每个分区的至少 一个输入。(一般情况下,构建这样一个测试套件实际上是不可能的,可以把它看成是一个不能达到的理想状态。)
集合的分区可以将集合分割为多个子集,并使得初始集合中的每个元素都恰好属于一个子集。例如,对于isBigger(x, y),可能的输入集合为所有整数的成对组合。对这个集合我们可 以将其划分为7个子集:
x为正,y为正 x为正,y为负 x = 0,y = 0
x为负,y为负
x为负,y为正
x = 0,y≠0 x≠0,y≠0
如果使用来自每个子集的至少一个值对函数实现进行测试,就非常有可能(不一定)暴露可 能存在的错误。
对于多数程序,适当地划分输入空间说起来容易,做起来就太难了。我们通常需要将代码和 规范结合起来,进行各种路径探索,并在此基础上发展出一种启发式方法。基于代码探索路径的 启发式方法称为白盒测试,基于规范探索路径的启发式方法称为黑盒测试。
###黑盒测试
构建黑盒测试时,不需要查看要测试的代码。黑盒测试允许测试者和开发者来自不同的人群。当我们这些讲授编程课程的教师为分配给学生的问题集合生成测试案例时,就是在建立黑 盒测试套件。商业软件的开发者经常要配备一个质量保证团队,这个团队在很大程度上是独立于 开发团队的。
生成测试套件时,代码中的错误可能会潜伏到测试套件中,上面这种团队之间的独立性可以 减少这种可能性。举例来说,程序编写者可能做了一个错误的隐含假设,即不能使用负数调用函 数,那么如果由这个人构建程序的测试套件,就很有可能继续重复这个错误,不使用负数参数测 试这个函数。
黑盒测试的另外一个好处是,具体实现发生变化时,这种测试仍然适用。因为生成测试数据 与具体实现没有关系,所以具体实现改变时,测试不需随之改变。
我们前面说过,生成黑盒测试数据的有效方法是通过规范探索测试路径。看一下下面的规范:

def sqrt(x, epsilon):
'''
假设x和epsilon是浮点数
x>=0
epsilon>0
如果存在满足x-epsilon <= result*result <=x + epsilon的result,就返回result
'''

这个规范看上去只有两条路径:一条对应x = 0,一条对应x > 0。但常识告诉我们,尽管
测试这两种情形是必要的,但绝对不够。 还需要测试边界条件。测试列表时,边界条件包括空列表、只有一个元素的列表以及包含列
表的列表。测试数值时,典型的边界条件就是非常小的值、非常大的值和“正常”值。对于例子 中的sqrt函数,使用下表中的x和epsilon值应该比较理想。

xepsilon
0.00.0001
25.00.0001
0.50.0001
2.00.0001
2.01.0/2.0**64.0
1.0/2.0**641.0/2.0**64.0
2.0**64.01.0/2.0**64.0
1.0/2.0**64.02.0**64.0
2.0**64.02.0**64.0

前四行是一些典型的测试用例。请注意,x值包括一个完全平方数、一个小于1的数和一个根 为无理数的数。如果这些测试有任何一种没有通过,那么程序中肯定有错误需要修复。
其余几行测试了x和epsilon取特别大的值和特别小的值的情形。如果有任何一种测试失败, 说明程序有需要修改的地方。可能是程序中有错误需要修复,也可能需要修改规范以使它更容易 被满足。例如,当epsilon特别小的时候,还希望能找到合适的平方根近似值,那对程序的要求 就太高了。
还需要考虑的一个重要边界条件是别名,例如:

 def copy(L1, L2):
 '''假设L1和L2是列表
使L2和L1元素相同'''
 删除L2中的所有元素
删除L2的第一个元素 向空列表L2添加L1的元素
 L2.append(e)

多数情况下是有效的,但L1和L2引用同一个列表时,它就失效了。如果测试套件中没有包括像 copy(L, L)这样的函数调用,就永远不会发现这个错误。

###白盒测试
黑盒测试是必需的,但通常也是不够的。不检查代码内部结构,就不可能知道哪种测试用例 能提供新的信息。看看下面这个普通的例子:

def isPrime(x):
'''
假设x是非负整数
如果x是素数,则返回True,否则返回False
'''
	if x <=2:
	return False
	for i in range(2,x):
		if x%i == 0:
			return False
	return True

查看代码可知,因为测试条件为if x <= 2,所以0、1和2都可以作为一种特殊情形,都需要测试。如果不看这段代码,可能就不会测试isPrime(2),也就不会发现isPrime(2)这个函数 调用会返回False,错误地认为2不是质数。

构建白盒测试套件要比黑盒测试套件容易得多。规范经常是不完整的,也十分简单,这使得 我们很难估计黑盒测试套件对输入空间的覆盖程度。相比之下,代码中反映的路径则定义得非常 清楚,白盒测试套件对输入空间的覆盖程度相对也比较容易。实际上,现在就有一些商业工具可 以比较客观地测量白盒测试的完备程度。

如果一个白盒测试套件可以测试程序中所有潜在路径,那我们就可以认为它是路径完备的。 一般来说,路径完备不可能达成,因为这取决于程序中循环的次数和递归的深度。例如,一个阶 乘函数的递归实现对于每种可能的输入都有不同路径(因为不同输入的递归深度不一样)。
而且,即使一个路径完备的测试套件也不能保证发现程序中的所有错误。看下面的代码:

def abs(x):
'''
假设x是证书
如果 x>=0返回x,否则返回-x
'''
	if x < -1:
		return -x
	else:
		return x

从规范中可知,有两种可能的情形:x为负数,或者不为负数。这说明输入集合{2, -2}足以覆盖规范中的所有路径。这个测试套件对我们来说还有一个额外的惊喜:它同时也测试了程序 代码中的所有路径,所以看起来也是一个路径完备的白盒测试套件。美中不足的是,这个测试套 件忽略了这样一个事实:abx(-1)会返回-1。
尽管白盒测试有很多局限性,但它提供的一些经验准则仍然值得我们参考:

  • 测试所有if语句的所有分支。
  • 必须测试每个except子句
  • 对于每个for循环,需要以下测试用例:
    • 未进入循环(例如,如果使用循环遍历列表中的所有元素,则必须测试空列表);
    • 循环体只被执行一次
    • 循环体被执行多于一次;
  • 对于每个while循环:
    • 包括上面for循环中的所有用例;
    • 还要包括对应于所有跳出循环的方式的测试用例。例如,对于以while len(L) > 0 and not L[i] == e开始的循环,测试用例应该包括因为len(L)不大于0和因为L[i] == e而跳出循环的情况。
  • 对于递归函数,测试用例应该包括函数没有递归调用就返回、只执行一次递归调用和执行多次递归调用的情况。
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值