软件测试中常常需要测试函数/脚本/接口的参数取值情况,在参数数目不多,参数取值数目也不多的情况下,可以采取参数间取值交叉遍历的穷举测试。
以下面的参数配置为例。
param1.cfg
param1 0 1
param2 0 1 2
param3 0 1 2 3
穷举所有情况,可得2x3x4=24种,下面为python实现。
paramTest1.py
#!/usr/local/bin/python3.5 -u
import os
import sys
def getParam(paramCfgFile):
dict = {}
for line in os.popen('cat ' + str(paramCfgFile.strip())).readlines():
args = line.strip().split()
parameter = args[0]
dict[parameter] = []
values = args[1:]
for value in values:
dict[parameter].append(value)
return(dict)
def func(dict):
paramList = []
for i in range(len(dict.keys())):
key = list(dict.keys())[i]
values = dict[key]
paramListTemp = paramList[:]
paramList = []
for j in range(len(values)):
value = values[j]
paramString = str(key) + " " + str(value)
tempList = [paramString]
if i == 0:
paramList.append(tempList)
else:
for origList in paramListTemp:
tempListTemp = tempList[:]
tempListTemp.extend(origList)
paramList.append(tempListTemp)
return(paramList)
def printParamList(paramList):
for i in range(len(paramList)):
print(">>> Case " + str(i))
for param in paramList[i]:
print(param)
print("")
def main():
paramCfgFile = sys.argv[1]
dict = getParam(paramCfgFile)
paramList = func(dict)
printParamList(paramList)
###################
## Main Function ##
###################
if __name__ == "__main__":
main()
测试情况如下。
[liyanqing@bogon python]$ ./paramTest1.py param1.cfg
>>> Case 0
param1 0
param3 0
param2 0
... ...
Case 23
param1 1
param3 3
param2 2
当参数数目(以及取值数目)较多时,穷举测试中组合情况的个数急剧增加,以至于很快就会达到基本上无法测试的境地,以下面10个参数的配置表为例。
param2.cfg
param1 0 1
param2 0 1 2
param3 0 1 2 3
param4 0 1
param5 0 1 2
param6 0 1 2 3
param7 0 1
param8 0 1 2
param9 0 1 2 3
param10 0 1
测试情况如下:
[liyanqing@bogon python]$ ./paramTest1.py param2.cfg
... ...
>>> Case 27647
param6 3
param8 2
param5 2
param1 1
param10 1
param3 3
param4 1
param7 1
param2 2
param9 3
穷举测试中情况数目达到了惊人的27648种!这几乎是无法完成的测试。在这种情况下我们只能放弃完全的穷举测试,而采取更加灵活的方式。
在我们日常的测试工作中常采用下面的策略,既保证每个参数每个取值至少能取到一次,并且某个参数取值固定时,其它参数的取值随机选取,这样能够急剧缩小总体的测试用例数目到“num(param1_values) + num(param2_values) + ... + num(paramn_values)”。新测试脚本只需要更改“func”函数即可实现。
paramTest2.py
#!/usr/local/bin/python3.5 -u
import os
import sys
import random
def getParam(paramCfgFile):
dict = {}
for line in os.popen('cat ' + str(paramCfgFile.strip())).readlines():
args = line.strip().split()
parameter = args[0]
dict[parameter] = []
values = args[1:]
for value in values:
dict[parameter].append(value)
return(dict)
def func(dict):
paramList = []
for i in range(len(dict.keys())):
key = list(dict.keys())[i]
values = dict[key]
for j in range(len(values)):
value = values[j]
paramListTemp = []
paramString = str(key) + " " + str(value)
paramListTemp.append(paramString)
for k in range(len(dict.keys())):
if k != i:
otherKey = list(dict.keys())[k]
otherValues = dict[otherKey]
t = random.randint(0, len(otherValues)-1)
otherValue = otherValues[t]
paramString = str(otherKey) + " " + str(otherValue)
paramListTemp.append(paramString)
paramList.append(paramListTemp)
return(paramList)
def printParamList(paramList):
for i in range(len(paramList)):
print(">>> Case " + str(i))
for param in paramList[i]:
print(param)
print("")
def main():
paramCfgFile = sys.argv[1]
dict = getParam(paramCfgFile)
paramList = func(dict)
printParamList(paramList)
###################
## Main Function ##
###################
if __name__ == "__main__":
main()
同样拿10参数的配置文件测试。
[liyanqing@bogon python]$ ./paramTest2.py param2.cfg
>>> Case 0
param3 0
param2 2
param5 1
param7 1
param4 1
param10 0
param9 2
param1 1
param8 2
param6 2
... ...
>>> Case 28
param6 3
param3 1
param2 2
param5 0
param7 0
param4 1
param10 0
param9 0
param1 1
param8 0
测试用例数目缩减到29个,完全在可测范围内。
在实际的操作中,当参数数目(及参数取值数目)比较多时,我们一般执行优化脚本2~3次,以保证在参数随机取值的情况下覆盖尽量多的情况。一般这样测试没有出现crash等严重情况,可以估计认为其它测试出现crash的可能性也不大。