软件测试中常常需要测试函数/脚本/接口的参数取值情况,在参数数目不多,参数取值数目也不多的情况下,可以采取参数间取值交叉遍历的穷举测试。
以下面的参数配置为例。
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的可能性也不大。