禅道开发的数据制造
为什么开发ZenData
摘要:DevOps时代下面对自动化测试的要求越来越高,但如何能够将自动化测试规模化、工程化是每一个团队都会面临的巨大挑战。在这个挑战中,测试数据的生成、维护、解析又是重中之重。
一、时代背景
最近几年DevOps概念越来越火,各种DevOps平台也如雨后春笋一样涌现。但大家往往把重点放在在工具链的搭建上,而忽略软件研发最重要的本质。工具链搭建是容易的,有各种的开源软件可以满足需求。但工具链搭建起来之后应该怎么应用呢?DevOps是希望可以通过持续集成和持续交付来实现快速的响应,但这里面有一个前提,就是质量必须要保障。如果没有质量,持续集成和交付都是空谈。如何保证质量呢?就必须要上自动化测试。
二、存在问题
自动化测试无论单元测试、接口测试、功能测试都会面临一个挑战,即如何能够做到大规模、工程化的自动化测试。这里面会牵扯到很多方面的技术:测试环境、测试手段、测试资源、测试管理等等,但这里面最最重要的一环是测试数据的管理。
如果测试数据无法做到灵活、大规模的管理,那么自动化测试就始终无法做到规模化,无法起到快速验证、快速集成、快速交付的目的。
三、目前解决方案
目前测试数据是如何来维护的呢?绝大部分的团队还是停留在手工维护阶段。手工造数据,手工维护,成本之高,可想而知。个别有能力的测试人员,会自己写点脚本来生成数据。个别有开发资源的大厂,则自己组建团队来做专门的数据工厂。这些方案都不具备通用性,成本也极其高昂。
四、为什么来开发ZenData
业内研究理论方法的专家老师有很多,但提供落地工具的不多。我们经过讨论之后,觉得来开发一款所有人都可以使用的通用的测试数据生成工具,于是就有了ZenData这样一款测试数据生成工具。
ZenData则通过YAML文件,定义了一种简单的数据类型描述语法。使用者不需要对技术有过多了解,通过定义简单的字段取值列表、前缀后缀等配置,即可实现测试数据维护的目的。简洁、高效、灵活,是做单元测试、接口测试、功能自动化测试、性能测试、压力测试、打桩mock的有力帮手。
ZenData通过简单的range定义实现了区间、步长、随机、引用、重复、SQL查询等方式,通过简单的规则可应对各种变化。ZenData只有一个可执行文件,支持HTTP模式,还可以对数据进行反向解析,可以输出txt、json、xml、sql等多种格式。
ZenData数据生成工具简介
摘要:ZenData使用YAML来作为数据类型配置文件实现了数据的生成和解析。ZenData可以用于手工测试场景下面测试数据的准备,也可以用于自动化测试脚本里面的数据生成和解析。还可以一键生成海量数据用于性能和压力测试。
一、ZenData的实现原理
ZenData使用YAML来作为数据类型配置文件。对于每一种类型的数据来讲,我们都可以将其拆分成若干的字段。比如我们要测试一个用户的订单表,会有订单的id,用户id或者账户名,订单的名称,订单的金额,订单的时间,订单状态等等字段。我们可以针对每一个字段配置其取值的范围。比如订单id,我可以定义为从1到10000,用户id可以是1-100。这样每一个字段都有了一个取值范围列表。当ZenData来生成数据的时候,从每一个字段里面依次取一个值,将其拼接在一起,就形成了一条记录。大家可以想象成每个字段都是一个转盘,按照自己的频率进行旋转,每一次旋转都从中取出一个值,和其他的字段进行组合。
上面说的是最基本的的工作原理,ZenData还提供了步长、随机、循环、引用等多种定义方式,我们会在接下来的手册里面展开讲。
二、ZenData的用途
ZenData主要两大功能:数据生成和数据解析。通过一个配置文件,可以使用ZenData生成您想要的各种数据。同样也可以对某一个数据文件,指定其数据类型定义的配置文件,完成到结构化数据的解析。
ZenData可以用于手工测试场景下面测试数据的准备,也可以用于自动化测试脚本里面的数据生成和解析。还可以一键生成海量数据用于性能和压力测试。
三、ZenData主要的特点
- 简单无依赖,只有一个可执行文件,即可满足命令行生成和HTTP接口两种数据生成服务。
- 使用配置文件来生成数据,使用人员不需要有开发知识,即可上手应用。
- 提供了功能强大的语法,分组、区间、步长、循环、随机、格式化和前后缀等,配置灵活性极强。
- 支持从文本文件中读取数据,方便用户对字段取值进行精确控制。
- 提供了Excel表格数据的标准SQL查询接口,使用更加灵活。
- 使用预制的序列(ranges)、实例(instances)、配置(config)对定义进行复用,以解决复杂数据格式的定义。
- 语法支持继承和扩展,为定义文件间的复用提供方便。
- 可以反向解析数据,可以对程序的输出进行解析,方便自动化测试脚本进行比对。
- 发行包內置了基础业务数据的定义文件(不断完善中)。
- 提供了HTTP接口数据生成服务,各种语言都可以方便调用。
如何获得支持
一、关于开源软件技术支持的误读
国内很多朋友认为开源软件的作者理所应当提供免费的技术支持,其实这是一种误解。
开源软件大家可以免费使用,彼此并没有形成购买行为,所以开源软件都会声明没有技术支持的义务。
我们会尽我们所能为大家提供即时的支持,只要你的提问清楚,耐心有礼貌的提问,我们都会尽力帮大家解决问题。
我们也呼吁国内开源软件的用户对开源软件的作者多一些支持,这样才能形成互惠互利的开源环境。
二、提问请不要:
1. 请不要带主观色彩。比如:太难用了,太麻烦了,强烈建议,很急之类的词语。
2. 请不要重复提问。比如你在我们网站问答提问,就不要在QQ群提问。反之亦然。
3. 请不要说无关的话。比如有人在吗?我是小白,我是菜鸟之类的话。有问题直接描述即可。
三、提问请一定:
1. 请一定要看文档:绝大部分的问题都可以在文档中找到。
2. 请一定要上截图:不要自己推测问题,请一定要上截图。
3. 请一定要找到日志:zentao/tmp/log/下面找到php开头的新日志。
4. 问题解决之后请一定给我们一个回馈,以帮助我们积累经验。
5. 如果你有时间, 给我们的技术支持人员一句谢谢 ,我们也会很开心的回应:不客气。
快速入门
安装部署
一、Windows下载安装ZenData
- 从https://zd.im/download.html下载ZenData最新版文件;
- 解压后进入相应目录,如c:\zd;
- 执行zd.exe -h获取使用帮助;
- 执行zd.exe -e获取命令示例;
- 首次执行时,请根据提示选择工具的语言;
- 根据提示执行setx Path命令,将zd.exe加入$PATH环境变量,以便于在任意目录中执行。
二、Linux下面下载安装ZenData
- 从https://zd.im/download.html下载ZenData最新版文件;
- 解压后进入相应目录,比如~/zd
- 执行./zd -h获取使用帮助;
- 执行./zd -e获取命令示例;
- 首次执行时,请根据提示选择工具的语言;
- ZenData将自动将zd命令加入用户环境变量$PATH,以支持在任意目录中执行。
将ZenData加入$PATH系统环境变量中
一、Windows系统
1. 在命令行输入sysdm.cpl,打开系统属性窗口;
2. 依次点击"高级"标签、"环境变量"按钮,打开环境变量编辑窗口;
3. 在上部"用户变量"列表中,点击"编辑"按钮修改Path变量;若无Path变量,则点击"新建"按钮;
4. 填入或追加zd.exe文件所在的目录绝对路径,Win7中为单行编辑模式,路径间用英文分号隔开;
5. 重新打开命令行窗口,使设置生效。
二、Linux或Mac系统
1. 编辑用户目录下的.bash_profile文件;
2. 在文件末尾添加export PATH=$PATH:<zendata文件所在目录绝对路径>;
3. 执行source ~/.bash_profile使设置生效。
命令行参数说明
以下是ZenData命令行参数的说明:
数据生成相关
-d --default 默认的数据格式配置文件。
-c --config 当前场景的数据格式配置文件,可以覆盖默认文件里面的设置。
-o --output 生成的数据的文件名。可通过扩展名指定输出json|xml|sql|csv|xlsx格式的数据。默认输出原始格式的文本数据。
-n --lines 要生成的记录条数,默认为10条。
-F --field 可通过该参数指定要输出的字段列表,用逗号分隔。 默认是所有的字段。
-t --table 输出格式为sql时,需通过该参数指定要插入数据的表名。
--dns 指定数据源连接字符串,结合表名使用,可直接插入数据到MySQL数据库表。
--clear 插入数据前,删除已有数据。
-T --trim 输出的字段去除前后缀,通常用在生成SQL格式输出和数据反向解析命令中。
-H --human 输出可读格式,打印字段名,并使用tab键进行分割。
-r --recursive 递归模式。如不指定,默认为平行模式。平行模式下各个字段独立循环。
递归模式下每个字段的取值依赖于前一字段。可增强数据的随机性。
-R --root 指定数据生成命令的执行目录,默认为当前目录。
內置数据查看
-l --list 列出当前目录下所有的用户数据定义。
-L 列出ZenData安装目录下所有数据定义。
-v --view 查看当前目录下某个用户数据定义的详细信息。
-V 查看ZenData安装目录下某个数据定义的详细信息。
从SQL生成数据
-i --input 指定一个数据库Schema或文章文本文件,解析生成yaml配置文件。需通过-o参数指定一个输出的目录。
-D --decode 根据指定的配置文件,将通过-i参数指定的数据文件解析成json格式。
HTTP服务相关
-p --port 在指定端口上启动Web服务。可通过页面管理测试数据、通过接口请求JSON格式的数据。服务模式下接口只支持数据生成。
-b --bind 监听的ip地址,默认监听所有的ip地址。
-R --root 运行HTTP服务时根目录。客户端可调用该根目录下面的配置文件。如果不指定,取zd可执行文件所在目录。
帮助相关
-h --help 打印帮助。
-e --example 打印数据定义文件示例。
命令行调用示例
以下是ZenData命令的一些示例:
数据生成
$>zd.exe -d demo\default.yaml # 根据-d参数指定的配置文件生成10条记录。
$>zd.exe -c demo\default.yaml # 根据-c参数指定的配置文件生成10条记录。
$>zd.exe -c demo\default.yaml -r # 根据-c参数指定的配置文件,采用递归的方式生成10条记录。
$>zd.exe -d demo\default.yaml -c demo\test.yaml -n 100 # -c和-d两个文件的配置合并,输出100条记录。
$>zd.exe -d demo\default.yaml -c demo\test.yaml -n 100 -o test.txt # 输出原始格式的数据。
$>zd.exe -d demo\default.yaml -c demo\test.yaml -n 100 -o test.json # 输出json格式的数据。
$>zd.exe -d demo\default.yaml -c demo\test.yaml -n 100 -o test.xml # 输出xml格式的数据。
$>zd.exe -d demo\default.yaml -n 100 -o test.sql -t user # 输出针对user表的insert语句。
$>zd.exe -d demo\default.yaml -n 100 -o test.sql -t user --trim # 输出针对user表的insert语句,去掉前后缀。
$>zd.exe -c test\test-sql.yaml -t zendata.table_a --trim -dns mysql://root:P2ssw0rd@127.0.0.1:3306/zendata#utf8 --clear # 插入数据到MySQL数据源。
內置数据查看
$>zd.exe -l # 列出所有內置数据。
$>zd.exe -v system.address.v1 # 查看內置Excel文件system/address/v1.xlsx中的数据表。
$>zd.exe -v system.address.v1.china # 查看內置Excel文件china数据表中的数据。
$>zd.exe -v system.ip.v1.yaml # 查看內置IP地址的Instances数据。
从SQL生成YAML数据定义
$>zd.exe -i demo\zentao.sql -o db # 根据SQL生成各表的yaml定义文件,存储到db目录里面。
从文章生成YAML数据定义
$>zd.exe -i demo\article.txt -o demo # 转换文章为yaml配置,输出到demo目录下。
数据反向解析
$>zd.exe -c demo\default.yaml -i test.txt --decode # 将-i指定的文件根据-d参数的配置进行解析。
HTTP服务
启动服务:
$zd.exe -p 80 # 监听80端口,以zd.exe文件所在目录为根目录。
$zd.exe -p 80 -R d:\zd\def # 监听80端口,以d:\zd\def为根目录。
客户端调用:
$curl http://loclahost/?d=default.yaml&c=config.yaml&n=100&o=test.sql&t=user # 通过GET方式指定服务器端配置文件。
$curl http://loclahost/?default=default.yaml&output=test.sql&table=user # 参数名可以用全拼。
$curl -d "default=...&config=...&lines=10" http://localhost/ # 可以通过POST方式上传配置。
內置数据定义示例
随着ZenData发行文件,我们打包了如下的內置数据定义。执行ZenData命令时,软件会从用户当前目录和ZenData部署目录寻找数据定义和资源。
- data目录: 存放Excel格式的基础数据,如国家、地区、人名和中文词语等。
- yaml目录: 系统内置的一些数据定义,如账号、域名、邮箱、日期和文章等。
- users 目录: 用于存放用户自己定义的一些数据。
- demo 目录: 一些演示的例子。
YAML定义语法总览
以下为一个标准的YAML定义文件,各元素含义请见注释。更多详细说明,请参见本手册后续章节。
title: zendata数据配置语法说明
desc:
# 文件组成
# zendata以yaml格式的文件来定义各个字段的格式。
# yaml文件整体由文件说明和字段定义两部分组成。
# 文件说明
# title: 标题,可以用简短的文字概要描述该文件定义的数据类型。
# desc: 描述,可以用多行文本来详细描述该文件定义的数据类型,非必选项。
# author: 作者,非必选项。
# version:版本号,非必选项。
# 字段列表
# 字段定义部分都放在fields这个定义里面。
# 一个yaml文件可以包含一个或者多个字段。
# 字段列表以-field定义开始。
# 一个字段可以通过fields属性定义它的子字段。
# 字段定义
# field: 字段名,仅支持英文、数字、下换线和.
# range: 列表范围,最重要的定义。
# loop: 循环次数,可以定义某一字段循环多少次。
# loopfix: 每一次循环时的连接符。
# format: 支持格式化输出。
# prefix: 该字段的前缀。
# postfix: 该字段的后缀。
# length: 该字段的长度。如果不通过分隔符区分,则需要指定字段长度,单位是字节。
# leftpad: 左填充的字符。如果长度不够,可指定左填充的字符。默认是以空格左填充。
# rightpad: 右填充的字符。如果长度不够,可指定右填充的字符。
# config: 可以引用另外一个文件里面的定义。
# from: 引用某一个定义文件。
# use: 使用被引用文件中定义的若干实例。all代表使用所有。
# select: 如果引用的文件是excel表,可以查询里面的某一个字段。
# where: 如果引用的文件是excel表,可以使用查询条件。
# loop定义
# 可以使用一个数字来指定字段循环的次数,比如loop:2。
# 可以使用区间来定义字段循环的次数。比如loop:2-10。
# range定义
# 使用逗号连接不同的元素。比如 range: 1,2,3。
# 元素也可以是一个区间。比如 range:1-10, A-Z。
# 区间可以通过冒号:来指定步长。比如 range:1-10:2。
# 步长可以是小数。比如 range: 1-10:0.1。
# 步长可以是负数。比如 range:100-1:-1。
# 区间可以通过R来指定随机。比如 range: 1-10:R,随机和步长只能二选一。
# 可以通过一个文件来指定列表。比如range: list.txt。文件名是相对路径时,以配置文件为基准计算。
# 可以通过{n}的方式来重复某一个元素。比如 range: user1{100},user2{100}
# 如果区间或者几个元素需要重复,需要用[]括起来。比如 range: [user1,user2,user3]{100}
author: zentao
version: 1.0
fields:
- field: field_common # 默认的列表类型,通过逗号隔成若干区间。
range: 1-10, 20-25, 27, 29, 30 # 1,2,3...,10,20,21,22...,25,27,29.30
prefix: "" # 前缀
postfix: "\t" # 后缀,特殊字符加引号,否则无法解析。
- field: field_step # 区间指定步长。
range: 1-10:2, 1-2:0.1 # 1,3,5,7,9,1, 1.1,1.2...,2
postfix: "\t"
- field: field_random # 区间指定随机。随机属性R同步长不能同时出现。
range: 1-10:R # 1,5,8...
postfix: "\t"
- field: field_loop # 自循环的字段。
range: a-z # a|b|c ...
loop: 3 # 循环三次
loopfix: _ # 每次循环的连接符。
postfix: "\t"
- field: field_repeat # 通过{}定义重复的元素。
range: user-1{3},[user2,user3]{2} # user-1,user-1,user-1,user2,user2,user3,user3
postfix: "\t"
- field: field_format # 通过格式化字符串输出。
range: 1-10 # passwd 1,passwd 2,passwd 3 ... passwd10。
format: "passwd%02d" # 用%02d补零,使密码整体保持8位。
postfix: "\t"
- field: field_length # 指定宽度。
range: 1-99 # 01\t,02\t,03\t..., 99\t
length: 3 # 包含前后缀的宽度。
leftpad: 0 # 宽度不够时,补充的字符。
postfix: "\t"
- field: field_text # 从一个文件中随机读取。
range: users.txt:R # 相对当前文件路径。
postfix: "\t"
- field: field_yaml # 引用其他的定义文件整体内容。
range: test/test-nested2.yaml{3} # 相对当前文件路径。
postfix: "\t"
- field: field_use_config # 引用其他的config定义文件。
config: number.yaml # 相对当前文件路径,config内包含单个字段。
postfix: "\t"
- field: field_use_ranges # 引用內置的定义文件,该文件定义了多个range,他们共享了一些field层面的属性。
from: zentao.number.v1.yaml # 引用yaml/zentao/number/v1.yaml文件里面的ranges定义。
use: medium # 使用该文件中定义的medium分组。
postfix: "\t"
- field: field_use_instance # 引用其他的定义文件,该文件定义了多个实例。
from: ip.v1.yaml # yaml/ip/v1.yaml
use: privateC,privateB # 使用该文件中定义的privateC和privateB两个实例。
postfix: "\t"
- field: field_use_excel # 从excel数据源里面取数据。
from: address.cn.v1.china # 从data/address/v1.xlsx文件中读取名为china的工作簿。
select: city # 查询city字段。
where: state like '%山东%' # 条件是省份包含山东。
rand: true # 随机取数据
postfix: "\t"
- field: field_with_children # 字段多层嵌套
fields:
- field: child1
range: a-z
prefix: part1_
postfix: '|'
- field: child2
range: A-Z
prefix: part2_
postfix: '|'
- field: child_with_child
prefix: part3_
postfix:
fields:
- field: field_grandson
prefix: int_
range: 10-20
postfix: