未标注版本的工具使用最新版即可
文件名 : GlobalConfig.xml
作用:设置所有项目通用的默认配置参数
<root>
<currentHost>mysqlcurrentHost>
<httpProxy enabled="false" ip="127.0.0.1" port="8888">httpProxy>
<logThreshold>infologThreshold>
<responseBody length="0">trueresponseBody>
<autoImportData>falseautoImportData>
<RunCases>RunCases-steamer-134.xmlRunCases>
<reportPublishServer ip="192.168.0.194" svcip="192.168.0.58" port="22" username="****" password="****" path="/home/yxd/report/html/">reportPublishServer>
<headers>
<header name="Content-Type" value="application/json;charset=UTF-8">header>
<header name="Accept" value="application/json, text/plain, */*">header>
headers>
<params>
params>
root>
- currentHost:待测系统默认数据库类型(只是用来决定使用哪种数据库驱动程序),该参数可以在脚本中通过指定使用哪个数据库实例而覆盖。
- httpProxy: http代理设置,设置为true时,会通过代理发送http请求(如fiddler,charles之类的工具开启的代理。用于跟踪调试请求数据包,执行环境如果没有开启代理则请求会失败)
- logThreshold:日志级别,枚举值。级别越低日志越详细。
- responseBody:日志是否显示请求返回体 设置为true时,可以额外设置展示日志最大长度,0为显示完整日志。
autoImportData : 测试执行前执行指定的SQL文件导入基础数据(历史功能现在没启用)- RunCases : 指定一个默认的项目用例配置文件,该参数可以通过启动时的命令行参数(run=文件名.xml)覆盖
- reportPublishServer : 用于发布测试报告的Nginx服务器地址,因为nginx是基于58容器云部署的,所以这里有两个IP,58是masterIP,194是nodeIp,账户名密码是用来登录node后通过ftp上传报告文件的。path是nginx的publish路径。 port是ftp端口,另有一个web访问端口是 32167,这是在创建nginx应用时设置的 (该功能属于与容器云系统绑定的功能,如脱离容器云需要另外部署docker_nginx容器以及K8S)
- headers : 公共请求头,脚本中所有HTTP请求都会默认带上这些请求头,可以在脚本中通过设置同名header覆盖此参数值
- params :全局参数,在此处设置的参数,可以在所有脚本中通过 ${参数名}来引用。可以在脚本中覆盖
文件名 : RunCases-[项目名]-[环境标识].xml 如 RunCases-steamer-demo.xml
作用:针对具体项目设置项目中通用的配置参数(参数适用范围比全局的小)
<suite name="容器云冒烟测试">
<needMailReports>falseneedMailReports>
<reportMailTo>
[email protected]
reportMailTo>
<webhooks>
<webhook enabled="false" type="dingtalk">
https://oapi.dingtalk.com/robot/send?access_token=xxxxxxxx
webhook>
webhooks>
<project name="容器云" enabled="true">
<params>
<param name="rootUrl" value="http://192.168.0.134/">param>
<param name="loginUrl" value="http://192.168.0.134/api/user/signin">param>
<param name="username" value="xxx">param>
<param name="password" value="xxxxxx">param>
<param name="masterip" value="192.168.0.134">param>
<param name="master_username" value="xxx">param>
<param name="master_pwd" value="xxx">param>
<param name="node01_ip" value="192.168.0.135">param>
<param name="node01_username" value="xxx">param>
<param name="node01_pwd" value="xxx">param>
<param name="node02_ip" value="192.168.0.136">param>
<param name="node02_username" value="xxx">param>
<param name="node02_pwd" value="xxx">param>
params>
<dbs>
<db name="steamer">
<param name="dbHostPort" value="192.168.0.134:3306/steamer">param>
<param name="dbUsername" value="xxx">param>
<param name="dbPassword" value="xxxx">param>
db>
dbs>
<switchs>
switchs>
<cases priorityLevel="1">
<case enabled="true" casetype="function" name="资源管理" filepath="case/容器云/单接口/容器云_应用管理-lzq.xls" sheet="域名管理" priority="0">case>
<case enabled="true" casetype="function" name="资源管理" filepath="case/容器云/单接口/容器云_资源管理-lzq.xls" sheet="主机管理" priority="2">case>
<case enabled="true" casetype="function" name="资源管理" filepath="case/容器云/单接口/容器云_资源管理-lzq.xls" sheet="集群管理" priority="3">case>
<case enabled="true" casetype="function" name="资源管理" filepath="case/容器云/单接口/容器云_资源管理.xls" sheet="网络管理" priority="3">case>
<case enabled="true" casetype="function" name="资源管理" filepath="case/容器云/单接口/容器云_资源管理.xls" sheet="共享存储" priority="3">case>
cases>
project>
suite>
- suite : 当前测试套件的名称,会在测试报告中体现
- needMailReports:是否需要发送测试报告邮件
- reportMailTo : 测试报告发送对象,多个油箱使用分号分隔
- webhooks : 通过回调推送测试结果信息,这里存储的是回调地址
- enabled: 是否启用
- type:枚举值,暂时只支持dingtalk(钉钉机器人)
- project :项目信息配置
- name :项目名称(需要与case目录中的项目目录名称对应)
- enabled :是否启用
- params :项目参数,key-value结构,此处定义的参数可以在本项目脚本中使用${参数名}方式调用。当前配置文件样本主要是定义了一些系统访问路径,账户信息,以及容器云的主从服务器信息
- dbs : 数据库信息
- db : 数据库实例
- name : 数据库别名,该别名可以在脚本中引用,用于指定当前步骤使用哪个数据库
- param : 自定义参数
- name : dbHostPort(数据库连接字符串) 、 dbUsername(用户名) 、 dbPassword(密码)、dbType(数据库类型)
dbType字段说明 : 如这里不设置dbType则取全局文件中的currentHost,否则取当前字段值。 现在框架支持数据库类型为 mysql、postgresql- value : name对应的值
- switchs :用例开关,可通过case字段的属性(比如name,casetype等)控制case是否运行
- cases: 用例脚本配置
- priorityLevel : 用例执行优先级,取值为正整数,数值越小优先级越高。默认值为3,case的prioirty数值大于此数值将不会执行
- enabled : 是否启用
- casetype:用例类型,枚举值,支持 business和function
- name : 用例名称
- filepath : 用例脚本文件路径(excel格式)
- sheet :用例脚本文件的分页名称
- priority:用例优先级。与cases字段的 priorityLevel配合使用
注:除了suite、project、case之外,测试案例层级还有group和step,这两个层级会在脚本文件中体现
- group:用例分组,在这里我们将一组group相同的step定义为一个用例
- step:用例步骤,在接口测试中,一个step代表一次请求(http、ssh、sql、ftp)
用例脚本以Excel(*.xls)格式存储。 项目配置文件中的 case字段,定义了用例脚本的路径以及sheet页名称
<case enabled="true" casetype="function" name="资源管理" filepath="case/容器云/单接口/容器云_应用管理-lzq.xls" sheet="域名管理" priority="0">case>
脚本字段使用方法详解
- No: 表示用例步骤的编号,必填
- run:用于控制该步骤是否执行,为 【Y】 时该用例才会被读取执行。选填
- group :用例的场景分组,group相同的几条步骤组成一个测试场景
- desc :该用例的描述,选填。一般可用于描述当前step的目的
- method:操作方法,查看支持的方法列表
- url:http请求步骤,此处为接口请求路径,如填入相对路径则会自动与配置文档中的rootUrl参数进行拼接,其他请求类型
- methodParam:此处表示操作方法的参数,参数格式根据实际的操作方法而定
- checkpoint:检查点,对接口返回的数据进行验证,这里只能输入Json格式的参数
- Save : 保存接口返回的动态数据,或者配合setvar方法保存自定义数据
- header : 存储当前接口的自定义请求头信息,如果GlobalConfig.xml中有相同key的头,则会优先取脚本中的值,这是一个jsonarray
格式 :[{“name”:“Content-Type”,“value”:“text/xml; charset=UTF-8”}]
注意,这里定义的头信息只有当前这一次请求生效- sleep : 表示执行当前步骤前等待时间。单位为毫秒。留空则为默认值300毫秒
下面以容器云产品为例介绍脚本开发的过程 :
//例子
<case enabled="true" casetype="function" name="资源管理" filepath="case/容器云/单接口/容器云_应用管理-lzq.xls" sheet="域名管理" priority="0">case>
测试启动后,命令行日志信息如下图
测试完成后,会在\test-output\目录下生成HTML格式的测试报告以及ApiTestClass.log 日志文件
如配置并开启了webhook会在指定钉钉群中发送测试结果
用来表示步骤的编号,在一个Excel中建议唯一,该信息会在测试报告中展示(不唯一的话不会报错,但是在测试报告中会引起歧义,给定位异常造成麻烦)
标识该步骤是否执行,填入Y | y 时才会执行,留空或其他任何信息,都不会执行(这里是控制步骤是否执行的,与配置文件中的控制开关级别不一样)
步骤分组,group相同的步骤组成一个分组,一般用来表示一条测试案例,多个步骤从上至下顺序执行。
步骤描述,用于描述该步骤的操作目的,会在测试报告中展现
步骤执行的方法,框架中支持的方法如下:
{"id":"${bizAttrId01}"}
a=1&b=2
注意,由于全局配置文件中设置了默认的content-type为json,所以这里需要在脚本中header列设置请求头[{"name":"Content-Type","value":"application/x-www-form-urlencoded;charset=UTF-8"}]
{"file": "__bodyfile(../apitest.case.git/assets/upload.txt)"}
参数为字符串型,
// 参数实例:实际保存的参数键值为 => var01=参数一
{
"vartype":"string",
"varname":"var01",
"varvalue":"参数一"
}
参数为字符串型, 值为内置函数返回,
//实际保存的参数键值为 => beginTime1="yyyy-MM-dd HH:mm:ss" (当前的时间)
{
"vartype":"string",
"varname":"beginTime1",
"varvalue":"__now()" //内置函数
}
参数为字符串型,同时保存多个参数,实际保存的参数键值为 =>
var01=value01 var02=value02 var03=当月的第一天 如 2022/08/01
参数名和值以 ## 分隔 如键和值的数量不等则会抛异常
{
"vartype":"string",
"varname":"var01##var02##var03",
"varvalue":"value01##value02##__beginofmonth(yyyy/MM/dd)"
}
参数为列表,来源为字符串,实际保存的参数键值为 => var02=[101,102,103,104]
{
"vartype":"list",
"varname":"var02",
"varsource":"text",
"varvalue":"101,102,103,104"
}
参数为列表,来源为csv文件.实际保存的参数键值为 => var03=[[第一行数组],[第二行数组],[第三行数组]…]
{
"vartype":"list",
"varname":"var03",
"varsource":"file",
"filepath":"case/parameters/test1.csv" //驱动文件的相对路径,以下同
}
参数为列表,来源为csv文件,指定列头提取。实际保存的参数键值为 => var04=[Name列的值组成的数组]
{
"vartype":"list",
"varname":"var04",
"varsource":"file",
"filepath":"case/parameters/test1.csv",
"headername":"Name" //指定列头
}
参数为字典,实际保存的参数键值为 => var05=map[key1=value1,key2=value2…]
{
"vartype":"map",
"varname":"var05",
"filepath":"case/parameters/test2.csv"
}
// 参数实例
{
"ip":"${masterip}", //此处为引用配置文件中设置的参数
"username":"${master_username}",
"pwd":"${master_pwd}",
"cmd":"kubectl get pod -A -o wide |grep volume-tester-1",
"times":"3" //表示执行请求次数,默认为1
}
//参数实例
delete from auth_user where username like 'at-func-user%';
delete from auth_group where name like 'at-func-role%';
delete from auth_tenant where name like 'at-func-tenant%';
//参数实例
select * from auth_tenant where `name`='at-func-tenant01'
//save字段,可以对返回值进行提取,现在只支持取第一条数据。下面表示取字段为id信息保存到func_tenant_id参数
{
"extratortype": "sql",
"elements": [
{
"expression": "id",
"varname": "func_tenant_id"
}
]
}
//collection: 对应的集合名,类似table
//operate: 操作类型,find、insert、delete. find返回json;insert返回id;delete返回影响条数
//data: 为要insert的json数据
//filter: 过滤条件json数据, 相当于where
// find样例
{
"collection": "cmp_model_field",
"operate": "find",
"data": {},
"filter": {
"code": "${fcode}"
}
}
//delete样例
{
"collection": "cmp_asset_model_group",
"operate": "delete",
"data": {},
"filter": {
"code": "testgroup001"
}
}
//insert样例
{
"collection": "cmp_asset_model_group",
"operate": "insert",
"data": {
"tenantId": "${t001id}",
"code": "testgroup002",
"name": "testgroup002",
"editable": true,
"index": 9999,
"_class": "com.tiduyun.cmp.cmdb.model.entity.AssetModelGroup"
},
"filter": {}
}
方法参数,除上面例子中提到的方法对应的参数之外,另有一类特殊的参数,可以用于支持使用指定外部数据驱动文件,循环执行当前步骤(可参数化某些指定字段)
使用条件 :
1. case项目配置文件中,当前case的 casetype=function
2. method为http请求(get,post,put,delete)
{ //datadriver 指定驱动文件(*.xls)的相对路径
"datadriver":"case/容器云/单接口/datadriver/容器云_资源管理_data.xls",
// 驱动文件的sheet页名
"sheet":"集群管理-新增"
}
驱动文件格式:分为左右两个部分,如下图所示。
通过这种方式定义的测试步骤,测试执行时框架会先读取步骤信息覆盖父脚本对应字段的值,然后将其余字段拼接成Json请求体,按行逐一执行请求。实现参数化数据驱动的功能。
请求的路径,只有http或sql请求才需要输入该项,支持输入相对路径或绝对路径
检查点(断言)。参数为Json, 各字段描述如下
{
// extratortype默认值为 jsonpath,所以这里不提供该字段不影响使用
"checktype": "text",
"checkcontent": "$.message=为用户授权成功;$.code=0"
}
// 该参数表示 使用正则提取器,期望提取到的值 大于等于 1 。 如断言失败,则每十秒重试一次,一共重试三次。三次都失败,则抛出断言失败
{
"checktype": "text",
"extratortype": "regex",
"checkcontent": [
{
"key": "(?:Running|CrashLoopBackOff) +?(\\d.*?) ", //正则表达式
"value": "1",
"operator":">="
}
],
"onerror": "retry",
"retryinterval": "10" //重试间隔 单位为秒 retrycount 重试次数 默认为3次
}
operator : 比较操作符 ,支持 > 、 < 、 <= 、 >= 、 = 、<> 、 between 七种操作符,
1. 操作符为between时,value可不填,但是需要提供min和max两个参数
2. =与<> 可以支持字符串与整数比较,其他操作符只支持整数比较
//count样例,该参数表示,使用正则表达式 (Running) 来匹配请求的返回值,匹配到的次数期望值为 大于等于4
{
"checktype": "count",
"extratortype": "regex",
"checkcontent": [
{
"key": "(Running)", //正则表达式
"value": "4", //期望匹配次数
"operator": ">=" //比较操作符
}
]
}
{
"checktype": "file",
"checkcontent": "download/${func_imagedownload_filename01}",
"onerror": "retry",
"retryinterval": "5"
}
//sql样例,该参数表示 从指定的db中使用sql查询值,然后校验返回的第一条数据 两个指定字段的值
//1、checkcontent中记录字段和期望值,为jsonarray
//2、只校验sqlstatement查询出来的第一行数据
//3、需要指定dbalias(数据库别名)
{
"checktype": "sql",
"sqlstatement": "select * from auth_tenant where `name`='at-func-tenant01'",
"checkcontent": [
{
"field": "name",
"value": "at-func-tenant01"
},
{
"field": "description",
"value": "111111"
}
],
"dbalias": "steamer"
}
{
"checktype": "text",
"checkcontent": "$.message=2-50个字符",
"comparetype": "contains"
}
{
"checktype": "text",
"checkcontent": "$.list[*].name=autotest-tenant-func01", //$.list[*].name这个jsonpath返回的是一个列表
"isany": "true"
}
save字段有两种使用场景
jsonpath (不提供extratortype,则取默认值jsonpath)
regex
sql
//将expression提取的值保存到名为func_user_ids的参数中,此时保存的参数是一个列表
{
"extratortype": "jsonpath",
"elements": [
{
"expression": "$.list[*].id",
"varname": "func_user_ids"
}
]
}
//将expression提取的值保存到名为 func_app_id01的参数中,此时保存的参数是一个字符串
{
"extratortype": "jsonpath",
"elements": [
{
"expression": "$.list[0].id",
"varname": "func_app_id01"
}
]
}
//一次保存多个参数
{
"extratortype": "jsonpath",
"elements": [
{
"expression": "$.list[0].id",
"varname": "func_app_id01"
},
{
"expression": "$.list[0].name",
"varname": "func_app_name01"
}
]
}
//注意这里json表达式提取到的值为列表, 并且指定了索引为0,所以保存的是第一个元素的值,如不指定索引,则保存整个列表
{
"extratortype": "jsonpath",
"elements": [
{
"expression": "$.data[?(@.tenantName=='DEMO租户')].tenantId",
"varname": "tenantId",
"index": 0
}
]
}
//从行首开始取到第一个空格的字符串。场景是获取kubectl命令返回的namespace
{
"extratortype": "regex",
"elements": [
{
"expression": "^(.+?) ",
"varname": "healthyck1_namespace"
}
]
}
//group : 标示取匹配的第几个分组,默认为1(第一个分组小括号里的内容)类似于jmeter里的【模板 】
//index : 标示取匹配到的第几个值,默认为0 ,类似于jmeter里的匹配数字,但是没有随机取值功能
{
"extratortype": "regex",
"elements": [
{
"expression": "^(.+?) ",
"varname": "namespace"
},
{
"expression": " (volume-tester-1.+?) ",
"varname": "podname",
"group": 1, //group默认为1 ,这里可不提供此字段
"index": 1 // index默认为0,这里必须显式声明index
}
]
}
//varsource : 标示用来匹配的字符串是body还是header,默认为body,如果是header则还需要指定 headerkey,框架会把指定key的value全部提取出来,拼接成以##分隔的字符串后再用正则匹配提取
//headerkey : varsource为header时,需指定headerkey
{
"extratortype": "regex",
"elements": [
{
"expression": "DUBHE-ADMIN-TOKEN=(.+?);",
"varname": "token",
"varsource": "header",
"headerkey": "Set-Cookie"
}
]
}
// 其他字段设置 1、method为exeQuery 2、methodParam中填入sql脚本。比如select * from auth_tenant where `name`='at-func-tenant01'
//通过sql查询保存参数,可以将sql返回的第一行数据的多个字段保存为多个参数,除第一行外,其他数据将被舍弃
{
"extratortype": "sql",
"elements": [
{
"expression": "id",
"varname": "func_tenant_id"
}
]
}
指定请求头,同名header会覆盖配置文件中定义的值。
//样例
[{"name":"Content-Type","value":"application/x-www-form-urlencoded;charset=UTF-8"}]
//upload头样例
[
{
"name": "Content-Type",
"value": "multipart/form-data;boundary=----WebKitFormBoundaryTSncv9iAn3oKxb7K"
},
{
"name":"size", // 这个header是容器云自定义的
"value":8
}
]
休眠时间 表示执行请求后等待多长时间再执行下一步,单位是毫秒,默认为300
对于前面步骤中已经保存的参数,可以通过 ${参数名} 方式引用,在url、methodParam 、checkpoint、save、headers字段中均可以用
注意:如果methodParam中,比如接口的body中本身就带有 ${参数名} 一类的字符,需要在外面使用标识符包裹起来 例如有这样一个body:
{
"param":"${param1}",
"name":"tom"
}
为避免脚本执行时框架去解析这个参数,需要如下处理
{
"param":"${param1}",
"name":"tom"
}
框架内置了一些函数,可以通过 __函数名(参数) 的形式来引用。
__randomText() : 生成6位长度的随机字符与数字混合的文本
__randomText(20):生成20位长度的随机字符与数字混合的文本
__randomText(8,true): 生成8位长度的纯数字文本
__urlEncode(你好) : 生成对【你好】进行编码后的文本【%E4%BD%A0%E5%A5%BD】
__today() : 生成今日的日期 2021-11-08
__today(yyyy/MM/dd) : 生成今日的日期 2021/11/08
__yesterday() : 2021-11-07
__beginofyear() : 2021-01-01
__endofyear() : 2021-12-31
__beginofmonth() : 2021-11-01
__endofmonth() : 2021-11-30
__thismonth() : 2021-11
__lastmonth() : 2021-10
__now() : 2021-11-08 15:32:33
__base64encode(阿萨德) 输出 :6Zi/6JCo5b63
__base64decode(6Zi/6JCo5b63) 输出 : 阿萨德
__md5(123456) 输出 : e10adc3949ba59abbe56e057f20f883e
__uuid() 输出 : 9854b6ba-c6a6-41d2-bbf2-9b861cc93122
__escape(<script>alert('hello world')</script>) 输出 : %3cscript%3ealert%28%27hello%20world%27%29%3c/script%3e
__unescape(%3cscript%3ealert%28%27hello%20world%27%29%3c/script%3e)输出 : <script>alert('hello world')</script>
保存函数生成的值为参数 : 如需将函数生成的数据保存为参数,则只需在函数后添加 @参数名@ 即可
__randomText(10,true)@num1@
二级数据驱动文件是根据字段名动态拼接Json对象的,对于某些字段的值不是单纯的字符串格式,需要使用特殊标识表示出来。 比如 {“age”:18} 这个请求体,存储在excel单元格中无法指定字段类型,框架读取后生成的实际请求体为 {“age”:“18”},发送请求后可能会导致异常。所以需要在单元格中把数据类型标识出来
标识类型 :
num##100 : 表示该字段为数值型,值为100
- 标识符后面第一个字符为【{】 则表示该字段为Json对象
- 标识符后面第一个字符为【[】 则表示该字段为Json数组
- 标识符后面接null,表示该字段为null
- 标识符后面为空,表示请求体将不包含此字段
raw##{"key":"name","value":"leo"} // 表示该字段为Json对象
raw##[{"key":"name","value":"leo"},{"key":"age","value":20}] // 表示该字段为Json数组
raw##null // 表示该字段为null
raw## // 表示请求体将不包含此字段(模拟缺少字段时的用例)
框架支持以下几种运行时参数,可用于在命令行启动测试时,自定义某些参数的值
这些参数一般都是在持续集成环境下使用命令行启动测试时才需要使用
#实例 :
java -jar apitest.jar needmail run=RunCases-steamer-new.xml
#实例 这里定义的casepath 是根据jenkins中的job名而定的。也就是该job的workspace目录名称
java -jar apitest.jar casepath=apitest.case.git-steam
#实例 :
java -jar apitest.jar webhook run=RunCases-steamer-new.xml