viva-api-test 是一个 REST API 测试工具
- 声明式: 只需编写 JSON 配置文件,viva-api-test 可以友好地创建测试用例。
- 上下文变量: viva-api-test 可以保存接口调用的上下文变量,这些变量可以在随后的接口调用时被使用。
- 模块化: 封装每个测试用例成为模块,可以无痛地衔接每个测试用例,构造一个复杂的业务测试流程。
- 结果校验: 方便校验接口调用结果,错误提示友好。
- 插件配置: 可以编写插件脚本,对请求进行特殊处理。
# install
npm install -g viva-api-test
# 指定 JSON 所在目录,运行测试脚本
viva-api-test -d ./testcases
每一个 JSON 文件对应一个业务测试流程,viva-api-test 会对指定目录下所有 JSON 文件装载到测试工具中。
对应业务测试的名称描述
业务上下文预配置
业务测试的步骤,每个步骤都是一个单元测试
步骤描述
导入业务上下文变量到当前上下文,通常是通过 String 或者 Array 加载一个或者多个上下文变量。
例如:
// 假设业务上下文为
// {
// uid: 'vivatest',
// s: { token: 'xxxxxyyyyy' }
// }
// 按照如下配置获取到的当前上下文 { s: { token: 'xxxxxyyyyy' } }
"import": "s.token"
// 按照如下配置获取到的当前上下文 { uid: 'vivatest', s: { token: 'xxxxxyyyyy' } }
"import": ["uid", "s.token"]
如果需要对上下文变量进行重命名,需要通过 Object 来为指定上下文变量指定一个别名。
// 假设业务测试的上下文为
// {
// uid: 'vivatest',
// s: { token: 'xxxxxyyyyy' }
// }
// 按照如下配置获取到的当前上下文 { uid: 'vivatest', accessToken: 'xxxxxyyyyy' }
"import": {
"uid": "uid",
"accessToken": "s.token"
}
请求动作,默认为 'GET'
请求对应 host
请求路径,可以通过上下文变量进行配置。
"import": "voteId", // 导入业务上下文变量 voteId 到当前上下文中
"path": "vote/${voteId}" // 通过模板语法和当前上下文变量,替换 path 路径
请求的查询字符串对象,可以通过上下文变量配置,配置方法同 path。
请求体,可以通过上下文变量配置,配置方法同 path。
对返回的 body 进行验证 parameter
对返回的 body 进行等值比较。
将 body 返回的数据导入到业务上下文中,供后续接口使用。
例如:
// 这里保证了 body 的 data 字段中存在 id 属性
"rule": {
"data": {
"type": "object",
"rule": {
"id": "int",
"link": "string"
}
}
},
// 将 data.id 保存到业务上下文对应的 voteId 中
"context": {
"voteId": "data.id"
}
弥补配置文件无法满足的情况,调用指定过滤器方法处理请求参数。需要注意的是 filter 的执行时间是在构建请求时执行,filter 执行完毕后会立刻发送请求。
例如:
"filter": {
"md5": "body" // md5 为 filters 目录下的脚本方法,body 为需要处理的对象,目前只限定于 body path 和 query
}
{
"suit": "注册设备并创建投票", // 业务名称
"context": {
"uid": "vivatest" // 设置上下文变量,值为 vivatest
},
"steps": [{ // 业务接口调用步骤
"import": ["uid"], // 在此步骤导入上下文变量
"desc": "注册设备", // 步骤描述
"method": "PUT",
"host": "http://localhost:7001",
"path": "/user",
"body": { // 请求 body
"uid": "${uid}" // 在 body 中对上下文变量进行文本替换, ${param} 形式
},
// 假设返回数据 { status: 200, body: { result: true, token: "xxxxyyyyzzzz" } }
"rule": { // response body 参数验证
"result": "bool", // 验证 result 为 bool 类型
"token": "string"
},
"equal": { // response body 等值比较
"result": true // result 的值为 true
},
"context": {
"token": "token" // ${token} 为 body 返回的值,并设置为上下文变量
},
"filter": {
"md5": "body" // 调用同级 filters 目录内部的 md5 脚本对 body 进行加工处理
}
}, {
"import": ["token", "uid"], // 导入上下文变量 token
"desc": "上传投票信息",
"method": "POST",
"host": "http://localhost:7001",
"path": "/vote",
"query": {
"uid": "${uid}",
},
"body": {
"token": "${token}",
"title": "Which is the best?",
"img": "xxxx.png"
},
// 假设返回数据 { status: 200, body: { result: true, data: { id: 1111, link: 'http://www.snapvote.me/15' } } }
"rule": {
"data": {
"type": "object",
"rule": {
"id": "int",
"link": "string"
}
}
},
"equal": {
"result": true
},
"context": {
"voteId": "data.id" // 将 body 里的 data.id 设置为上下文变量 voteId
}
}, {
"import": ["token", "voteId"],
"desc": "获取投票详情",
"method": "GET",
"host": "http://localhost:7001",
"path": "vote/${voteId}", // 替换上下文变量
// 假设返回数据 {
// status: 200,
// body: { result: true, data: { id: 1111, title: 'aaaa', img: 'xxxx.png', result: [1, 2], type: 'lr' } }
// }
"rule": {
"data": {
"type": "object",
"rule": {
"id": "int",
"title": "string",
"img": "string",
"result": {
"type": "array",
"itemType": "int"
},
"type": [
"lr",
"rm"
]
}
}
}
}]
}