———————————————————-
点击上方可订阅关注我:蚂蚁质量!也可以加我微信进微信交流群。如果你觉得公众号对你有帮助,欢迎转发、推荐给他人。
————————————————————
上周天发布了一篇黑盒测试方法的文章,短短的一周时间阅读量超过1000,今天主要聊下白盒测试的方法。白盒测试和黑盒测试不一样而是基于代码和内部设计来设计测试用例,下面着重讲下以下七种白盒测试的方法。
1. 语句覆盖
语句覆盖是白盒测试中最基础的方法,它的目标很简单,就是确保代码中的每个语句至少被执行一次。这就好比我们要检查一本书里的每一句话有没有被读过,只要都读过一遍,就达到了语句覆盖的要求。虽然语句覆盖是比较弱的覆盖标准,但它是其他更复杂覆盖方法的基础。
以下面这段 Python 代码为例:
def calculate_bonus(sales_amount):
if sales_amount > 10000:
bonus = sales_amount * 0.2
else:
bonus = sales_amount * 0.1
return bonus
为了实现语句覆盖,我们可以设计这样的测试用例:
test_sales_amount = 15000
result = calculate_bonus(test_sales_amount)
print(result)
在这个测试用例中,sales_amount的值为 15000,大于 10000,所以会执行if分支中的语句,计算出奖金。这样,代码中的每个语句都至少执行了一次,达到了语句覆盖的要求。
2. 判定覆盖
判定覆盖就是设计若干个测试用例,运行被测程序,使得程序中每个判断的取真分支和取假分支至少经历一次。判定覆盖又称为分支覆盖。
判定路径覆盖( Decision-to-Decision PathsCoverage, DDPCoverage )是判定覆盖的一个变体。这里的判定指的是一个序列语句,其起始位置是函数入口或一个判定(如if,while, switch 等)的开始,结束位置是下一个判定的开始。
通过计算哪些判定路径已经走过,哪些没有走过,我们就可以得到 DDP 覆盖率了。其公式如下:DDP 覆盖=(至少被执行一次的判定路径数量)/(系统中判定路径总数)。
继续用上面的calculate_bonus函数,我们需要设计两个测试用例:
# 测试用例1:sales_amount大于10000
test_sales_amount1 = 15000
result1 = calculate_bonus(test_sales_amount1)
print(result1)
# 测试用例2:sales_amount小于等于10000
test_sales_amount2 = 8000
result2 = calculate_bonus(test_sales_amount2)
print(result2)
在测试用例 1 中,if条件为true,执行if分支;在测试用例 2 中,if条件为false,执行else分支。这样,每个判断的取真分支和取假分支都至少执行了一次,满足判定覆盖的要求。
3. 条件覆盖
条件覆盖关注的是判定语句中每个条件的所有可能取值。它要求每个条件的结果至少为true和false各一次。对于包含多个条件的判断语句,条件覆盖能更全面地检查代码的执行情况。
例如,有这样一段代码:
def check_conditions(a, b):
if a > 10 and b < 20:
return True
else:
return False
为了实现条件覆盖,我们可以设计如下测试用例:
# 测试用例1:a > 10, b < 20
test_a1 = 15
test_b1 = 15
result1 = check_conditions(test_a1, test_b1)
print(result1)
# 测试用例2:a <= 10, b >= 20
test_a2 = 8
test_b2 = 25
result2 = check_conditions(test_a2, test_b2)
print(result2)
在测试用例 1 中,a > 10为true,b < 20为true;在测试用例 2 中,a > 10为false,b < 20为false。每个条件的可能取值都被测试到了,满足条件覆盖的要求。
4. 判定条件覆盖
判定条件覆盖是判定覆盖和条件覆盖的结合,它要求不仅每个判断的所有可能结果都要执行,而且每个判断中的所有条件的可能取值也要至少出现一次。这意味着既要覆盖判断的真假分支,又要覆盖每个条件的真假情况。
我们来看下面这个函数:
def can_vote(age, is_citizen):
if age >= 18 and is_citizen:
return True
else:
return False
要满足判定条件覆盖,我们需要设计四个测试用例:
# 测试用例1:age >= 18, is_citizen为True
test_age1 = 20
test_is_citizen1 = True
result1 = can_vote(test_age1, test_is_citizen1)
print(result1)
# 测试用例2:age < 18, is_citizen为True
test_age2 = 15
test_is_citizen2 = True
result2 = can_vote(test_age2, test_is_citizen2)
print(result2)
# 测试用例3:age >= 18, is_citizen为False
test_age3 = 25
test_is_citizen3 = False
result3 = can_vote(test_age3, test_is_citizen3)
print(result3)
# 测试用例4:age < 18, is_citizen为False
test_age4 = 12
test_is_citizen4 = False
result4 = can_vote(test_age4, test_is_citizen4)
print(result4)
通过这四个测试用例,我们既覆盖了if语句的真假分支,又覆盖了age >= 18和is_citizen这两个条件的所有可能取值组合,满足判定条件覆盖的要求。
5. 条件组合覆盖
条件组合覆盖比前面几种覆盖方法更全面,它关注的是一个判断中所有条件的所有可能组合情况。这意味着要考虑到每个条件的真假值相互组合的所有可能性。
以一个简单的逻辑判断为例:
def check_logic(a, b, c):
if (a > 10 and b < 20) or c == 5:
return True
else:
return False
这个判断中有三个条件:a > 10、b < 20和c == 5。每个条件有两种取值(true或false),所以总共有 2×2×2 = 8 种可能的组合。为了实现条件组合覆盖,我们需要设计八个测试用例来覆盖这八种组合:
# 测试用例1:a > 10, b < 20, c == 5
test_a1 = 15
test_b1 = 15
test_c1 = 5
result1 = check_logic(test_a1, test_b1, test_c1)
print(result1)
# 测试用例2:a > 10, b < 20, c!= 5
test_a2 = 18
test_b2 = 12
test_c2 = 8
result2 = check_logic(test_a2, test_b2, test_c2)
print(result2)
# 测试用例3:a > 10, b >= 20, c == 5
test_a3 = 20
test_b3 = 25
test_c3 = 5
result3 = check_logic(test_a3, test_b3, test_c3)
print(result3)
# 测试用例4:a > 10, b >= 20, c!= 5
test_a4 = 22
test_b4 = 30
test_c4 = 10
result4 = check_logic(test_a4, test_b4, test_c4)
print(result4)
# 测试用例5:a <= 10, b < 20, c == 5
test_a5 = 8
test_b5 = 15
test_c5 = 5
result5 = check_logic(test_a5, test_b5, test_c5)
print(result5)
# 测试用例6:a <= 10, b < 20, c!= 5
test_a6 = 5
test_b6 = 12
test_c6 = 7
result6 = check_logic(test_a6, test_b6, test_c6)
print(result6)
# 测试用例7:a <= 10, b >= 20, c == 5
test_a7 = 3
test_b7 = 25
test_c7 = 5
result7 = check_logic(test_a7, test_b7, test_c7)
print(result7)
# 测试用例8:a <= 10, b >= 20, c!= 5
test_a8 = 6
test_b8 = 30
test_c8 = 9
result8 = check_logic(test_a8, test_b8, test_c8)
print(result8)
通过这八个测试用例,我们覆盖了所有条件的所有可能组合,满足条件组合覆盖的要求。
6. 路径覆盖
在程序控制流程图的基础上,导出可以执行的路径集合,设计测试用例。
Z 路径覆盖是路径覆盖的一个变体。路径覆盖是白盒测试最为典型的问题。着眼于路径分析的测试可称为路径测试。完成路径测试的理想情况是做到路径覆盖。对于比较简单的小程序实现路径覆盖是可能做到的。但是如果程序中出现多个判断和多个循环,可能的路径数目将会急剧增长,达到天文数字,以至实现路径覆盖不可能做到。为了解决这一问题,我们必须舍掉一些次要因素,对循环机制进行简化,从而极大地减少路径的数量,使得覆盖这些有限的路径成为可能。我们称简化循环意义下的路径覆盖为 Z路径覆盖。
这里所说的对循环化简是指,限制循环的次数。无论循环的形式和实际执行循环体的次数多少,我们只考虑循环一次和零次两种情况。也即只考虑执行时进入循环体一次和跳过循环体这两种情况。对于程序中的所有路径可以用路径树来表示。当得到某一程序的路径树后,从其根结点开始,一次遍历,再回到根结点时,把所经历的叶结点名排列起来,就得到一个路径。如果我们设法遍历了所有的叶结点,那就得到了所有的路径。当得到所有的路径后,生成每个路径的测试用例,就可以做到Z路径覆盖测试。
u 条件测试路径选择
当程序中判定多于一个时,形成的分支结构可以分为两类:嵌套型分支结构和连锁型分支结构。
对于嵌套型分支结构,若有n个判定语句,需要n+1个测试用例:
对于连锁型分支结构, 若有n个判定语句,需要有2n个测试用例,覆盖它的2n条路径
当n较大时将无法测试。
循环测试路径选择
循环分为 4 种不同类型:简单循环、连锁循环、嵌套循环和非结构循环。
u 简单循环
Ø 零次循环:从循环入口到出口
Ø 一次循环:检查循环初始值
Ø 二次循环:检查多次循环
Ø m 次循环:检查在多次循环
Ø 最大次数循环、比最大次数多一次、少一次的循环。
u 嵌套循环
对最内层循环做简单循环的全部测试。所有其它层的循环变量置为最小值:逐步外推,对其外面一层循环进行测试。测试时保持所有外层循环的循环变量取最小值,所有其它嵌套内层循环的循环变量取”典型”值。反复进行,直到所有各层循环测试完毕。
对全部各层循环同时取最小循环次数,或者同时取最大循环次数。
u 连锁循环
如果各个循环互相独立,则可以用与简单循环相同的方法进行测试。但如果几个循环不是互相独立的,则需要使用测试嵌套循环的办法来处理。
u 非结构循环
这一类循环应该使用结构化程序设计方法重新设计测试用例。
假设有这样一段代码:
def calculate_result(x, y):
result = 0
if x > 0:
result += x
if y > 0:
result += y
return result
这段代码有四条可能的执行路径:
x <= 0且y <= 0
x > 0且y <= 0
x <= 0且y > 0
x > 0且y > 0
为了实现路径覆盖,我们需要设计四个测试用例来覆盖这四条路径:
# 测试用例1:x <= 0, y <= 0
test_x1 = -5
test_y1 = -3
result1 = calculate_result(test_x1, test_y1)
print(result1)
# 测试用例2:x > 0, y <= 0
test_x2 = 8
test_y2 = -2
result2 = calculate_result(test_x2, test_y2)
print(result2)
# 测试用例3:x <= 0, y > 0
test_x3 = -4
test_y3 = 6
result3 = calculate_result(test_x3, test_y3)
print(result3)
# 测试用例4:x > 0, y > 0
test_x4 = 10
test_y4 = 12
result4 = calculate_result(test_x4, test_y4)
print(result4)
通过这四个测试用例,我们覆盖了代码中的所有可能路径,满足路径覆盖的要求。
7. 函数覆盖
有很多测试工具,例如 TrueCoverage , Logiscope 等,都提供了函数覆盖的概念,函数覆盖是针对系统或一个子系统的测试的,它表示在该测试中,有哪些函数被测试到了,其被测试到的频率有多大,这些函数在系统所有函数中占的比例有多大。函数覆盖是一个比较容易自动化的技术,同时也易于理解。其公式如下:
函数覆盖 =(至少被执行一次的函数数量)/(系统中函数的总数)
由于函数覆盖也是基于代码的,因此你可以把其归入到白盒的范畴内。
不同的白盒测试方法各有优缺点,在实际的软件测试中,我们需要根据项目的具体情况和需求,选择合适的测试方法或多种方法的组合,以确保软件的质量和可靠性。
看完这篇内容,麻烦大家点个赞或关注、转发。
-END-
作者简介:风随水
一个从事十五年测试和质量管理者
曾经深圳乃至全国最大最活跃软件测试QQ群群主
致力于质量管理和体系规范