软件测试中非常重要的一个工作就是生成和维护测试数据,而这个工作恰恰是繁琐、重复而极易出错的。无疑找到一种通用的数据生成方法是极具意义的。本文阐释了如何使用脚本语言 PHP,加上简单的 ini 配置文件来达到这个目的的。
测试的数据生成和维护在软件测试中是非常重要的一环。很多用例实际上就是在修改所测程序的输入数据以确保程序的逻辑是按照自己的预期进行地。
比如我们测试一个用户登录系统,我们需要测试正常用户名 + 正常密码、正常用户名 + 错误密码、错误用户名 + 错误密码等基本的用例。在执行用例之前,就需要事先在数据库中设置好相应的数据,比如有一条记录为正常用户名 + 正常密码,然后我们在登陆界面输入该用户名和密码,预期结果为正常登陆。
不同的程序有不同格式的输入数据。但不管格式千变万化,我们总可以把它们归结为基于行和列的格式,就像数据库中的表一样。一行为一条记录,每一条记录都有相同的字段组成,每一个字段有自己的数据格式,字段和字段之间可能有分隔符。
我们可以在执行每一个用例时,手工修改数据,然后再执行用例。但这样存在一些问题。
1. 重复,数据重用性差。当前用例所需的数据很有可能在下个用例中被破坏了。
2. 效率低,尤其是当数据格式比较复杂,而且又需要大量数据的时候。
3. 不灵活。但数据发生变动的时候,数据的维护成本会很高。
4. 容易出错。
那有没有一种方法来解决这个问题呢?答案是肯定的。下面我们一起来实现一个简单的工具来解决这个问题。
需要实现的基本功能
首先我们来列举一下这个软件测试工具需要实现的基本功能:
1. 通用性:能够描述各种不同格式的数据。
2. 扩展性:当需要新的数据格式时,可以任意扩展。
3. 易用性:配置文件不易复杂。
4. 跨平台:我们需要一款可以在windows、linux、FreeBSD等系统下面运行的工具。
我们选择的开发工具
我们选择的开发工具是 PHP,配置文件采用了 ini 格式的文件。
之所以选择 PHP,是因为 PHP 是解释性脚本语言,其弱类型的特点以及强大的数组、字符串处理功能,十分适合我们这种应用场合。而且 PHP 有着良好的扩平台性,使用 PHP 开发的脚本基本上不用修改就可以在各个平台下面运行。
之所以选择 ini 格式的文件来作为配置,是因为 ini 文件相比较于 xml 而言比较简单。而且程序处理起来也非常的方便。在 PHP 中使用 parse_ini_file 的内置函数就可以解析整个 ini 文件。
配置语法
首先我们需要来定义一下我们的配置语法。前面讲到,数据是由行和列组成,每一列中有若干字段,每一个字段有自己的生成数据类型,有自己的前缀,字段和字段之间还有分隔符。我们最终的配置语法格式如下:
清单一:example.ini
[field1]
datatype="list, range=[10-20]"
prefix="int_"
postfix=" "
[field2]
datatype="list, range=[A-Z, a-z]"
prefix="char_"
postfix=" "
[field3]
prefix=""
datatype="list, range=[abc,123,xyz, 100-110]"
postfix=" "
[field4]
prefix=""
datatype="list, range=[100-200:2]"
postfix=" "
我们来解释一下语法的格式:
1. 字段名使用[]引起来。后面使用 key=value 的形式来定义这个字段的属性。
2. 字段有三个基本的属性:datatype 指定字段的取值范围,prefix 设定字段的前缀,postfix 则设定字段的后缀。
3. datatype 中最基本的数据类型就是 list,一个无所不包的列表。你所需要指定的就是这个字段的取值范围参数 range。
4. range 参数可以采用 1-10 这样的区间表达,也可以用逗号“ , ”来连接多个区间或者元素。区间还可以指定递增的步长。
上面的 example.ini 文件中定义了四个字段,字段和字段之间使用两个空格分隔,第一个字段的取值范围为 10-20,前缀为 int_,第二个字段取值范围是大小写英文字母,前缀为 char_,第三个字段取值范围是混合的,第四个字段则从 100 到 200,递增步长为 2 。
清单二:生成的数据
int_10 char_A abc 100
int_11 char_B 123 102
int_12 char_C xyz 104
int_13 char_D 100 106
int_14 char_E 101 108
int_15 char_F 102 110
int_16 char_G 103 112
int_17 char_H 104 114
int_18 char_I 105 116
int_19 char_J 106 118
#p#
代码实现:
第一步:解析 ini 文件
error_reporting(0);
$iniFile = $argv[1]; // 第一个参数为配置文件。
$dataCount = $argv[2]; // 第二个参数为要生成的记录数。
$fields = parse_ini_file($iniFile, true); // 将 ini 配置文件转换为一个数组。
第二步:生成每一个字段的取值列表
foreach($fields as $fieldName => $field)
{
$list = array();
$equalPos = strpos($field['datatype'], '='); // 取得等号的为止。 range=[]
$range = substr($field['datatype'], $equalPos + 2, -1); // 取得 range 的列表(去掉了 [])
$items = explode(',', $range); // 得到所有的 item 元素。
/* 循环处理每一个 item,如果是一个区间,则调用 range 函数。 */
foreach($items as $item)
{
if(strpos($item, '-'))
{
list($min, $max) = explode('-', $item);
$list = array_merge($list, range($min, $max)); // 追加到 field 的 list 列表中。
}
else
{
$list[] = $item;
}
}
$field['list'] = $list; // 将最终的 list 列表赋值给 field 。
$field['pointer'] = 0; // 初始化这个列表的指针。
$fields[$fieldName] = $field; // 写回整个 fields 数组。
}
第三步:循环输出数据
/* 循环输出数据。 */
for($i = 0; $i < $dataCount; $i ++)
{
foreach($fields as $fieldName => $field)
{
$pointer = $field['pointer'];
/* 如果指针已经到到了列表的尾部,重新指向列表开始。 */
if($pointer == count($field['list'])) $pointer = 0;
echo $field['prefix']; // 输出前缀。
echo $field['list'][$pointer]; // 输出当前指针所对应的列表中的取值。
echo $field['postfix']; // 输出后缀。
$pointer ++;
$fields[$fieldName]['pointer'] = $pointer;
}
echo "\n";
}
这样我们用了不到 50 行的代码就完成了一个基本的数据生成工具。这其实已经可以满足基本的数据生成任务了。但是还需要进一步进行完善。
需要进一步完善的地方
第一:数据的扩展性
虽然 list 类型已经足够灵活,但有时候还无法满足需要。比如一个比较复杂的字段,由若干小字段组成。这时可以将这个复合字段再通过一个 ini 文件来定义,这样就有了无限可能。
比如,我们在 example.ini 文件中增加一个日期的字段,格式为 yyyy 年 mm 月 dd 日的格式
清单三:example.ini 中新增一个字段
[field5]
prefix=""
datatype="custom" " 定义这个字段的数据类型为 custom
datacfg="custom.ini" " 定义这个字段的配置文件为 custom.ini
postfix=""
清单四:custom.ini
[field5.1]
prefix=""
datatype="list, range=[1980-1999]"
postfix=" 年 "
[field5.2]
prefix=""
datatype="list, range=[1-12]"
postfix=" 月 "
[field5.3]
prefix=""
datatype="list, range=[1-31]"
postfix=" 日 "
这可以通过 php 中的递归函数来实现这个解析。即当解析到一个字段发现是自定义类型的时候,就读取这个字段所对应的 ini 配置文件,然后再解析它的每一个字段。具体的代码就不给出了,读者朋友们可以尝试实现。
第二:列表可以更加灵活
列表 range 参数还可以更加灵活,比如:
1. 可以指定步长:range=[1-100:2],表示从 1 到 100,步长为 2 递增。
2. 可以指定输出的格式:range=[1-100:2]&format=0.2f,这个地方的 format 可以是 sprintf 函数的格式标签。
3. 可以指定是否随机。现在生成的数据是按照列表中的顺序来生成的。可以通过一个 rand 参数来指定是否随机。
第三:不同的输出格式
我们现在输出的是行与列的格式,其实我们还可以定义其他不同的输出格式。比如输出为数据库的 insert sql 语句。输出为 xml 格式的数据。这些实现起来都不是特别的麻烦,代码中做些处理就可以了。
结束语
PHP 是一款非常优秀的脚本语言(虽然它主要用在 web 开发上)。使用 PHP 可以快速地写出很多小工具来帮助我们来完成某个任务。本文只是给出了一个数据生成方法的简单实现,各位读者朋友完全可以发挥自己的想象,开发出更加灵活、好用的工具来。具体到我们公司的应用,我们现在基本上可以使用这个工具来生成各种各样不同的测试数据。而且有了这些固定的测试数据,就可以实现自动化测试。
【编辑推荐】