1. Aest
项目地址:https://github.com/wangduandu...
功能强大的REST接口测试工具, Power By Jest, axios, superstruct, mustache, lodash
2. 特点
-
非常简单
: 大部分工作量在于写配置文件 -
请求模板
: 可以在配置文件中加入运行时变量,如/users/{{id}}
-
响应体结构验证
: 支持对响应体的字段类型进行严格校验,多字段、少字段、字段类型不符合预期都会报错 -
非常详细的报错提示
: 参见截图
3. 安装
yarn add aester
npm i aester -S
4. 使用
4.1. 编写测试用例
// filename 必须以 test.js结尾
const Ae = require('aester')
var testData = require('./test-data.js')
// 初始化配置文件
testData = Ae.init(testData)
describe('4XX 5XX error response test', () => {
test('Get User Info without sessionId', async () => {
await expect(Ae.send(testData.getOneUser, {id: '1'})).rejects.toHaveProperty('status', 403)
})
test('loginByEmail Fail Test', async () => {
await expect(Ae.send(testData.loginByEmail, {password: '111'})).rejects.toHaveProperty('status', 401)
})
})
describe('2XX success response test', () => {
test('loginByEmail Success Test', async () => {
// 对于符合预期的正向测试,不需要使用expect, 如果响应状态码是400以上,或者响应体结构不符合预期,
// 该测试用例会自动失败
const data = await Ae.send(testData.loginByEmail, {password: '000'})
Ae.share('sessionId', data.sessionId)
})
test('Get User Info', async () => {
await Ae.send(testData.getOneUser, {id: '1'})
})
})
describe('2XX success response with error body struct', () => {
test('StructError test', async () => {
var data = _.cloneDeep(testData.getOneUser)
data.resBodyStruct.test = 'number' // set a error struct
await expect(Ae.send(data, {id: '1'})).rejects.toHaveProperty('type', 'StructError')
})
})
4.2. 接口配置文件
// test-data.js
module.exports = {
$baseUrl: 'http://localhost:3000',
loginByEmail: {
desc: 'login',
req: {
method: 'post',
path: '/login',
headers: { 'content-type': 'application/x-www-form-urlencoded' },
data: 'email=wdd@cc.tt&password={{password}}',
params: {
_test: 1
}
},
resBodyStruct: {
sessionId: 'string'
}
},
getOneUser: {
desc: 'get user info',
req: {
path: '/users/{{id}}',
headers: {
'sessionId': '{{sessionId}}' // 如果share中有sessionId, 在请求发送时,会自动将{{sessionId}}替换成真正的值,否则会被替换成空字符串
}
},
resBodyStruct: {
id: 'string',
email: 'string',
password: 'string',
userName: 'string',
likes: 'array',
isAdmin: 'boolean'
}
},
createOneUser: {
desc: 'create user',
req: {
method: 'post',
path: '/users',
headers: {
'sessionId': '{{sessionId}}'
}
}
},
updateOneUser: {
desc: 'update user',
req: {
method: 'put',
path: '/users/{{id}}',
headers: {
'sessionId': '{{sessionId}}'
}
}
},
deleteOneUser: {
desc: '获取用户信息接口',
req: {
method: 'delete',
path: '/users/{{id}}',
headers: {
'sessionId': '{{sessionId}}'
}
}
}
}
4.3. 运行测试用例
在package.json加入
"scripts": {
"test": "jest"
}
然后运行npm test
4.4. 生成html测试报告
yarn add jest-html-reporter -D
4.4.1. 方法1
然后在package.json中加入如下字段
"test:report": "jest --reporters='jest-html-reporter'"
然后运行
npm run test:report
4.4.2. 方法2
创建jest.config.js在项目根目录
module.exports = {
verbose: true,
testEnvironment: 'node',
reporters: [
'default',
['./node_modules/jest-html-reporter', {
pageTitle: `operation api test ${process.env.testConfigEnv}`,
includeFailureMsg: true // 详细错误提示
}]
]
}
然后运行
npm test
5. 参看测试结果
5.1. 正常测试结果
PASS test/unit.test.js
PASS test/index.test.js
Test Suites: 2 passed, 2 total
Tests: 8 passed, 8 total
Snapshots: 0 total
Time: 1.864s
5.2. 接口报错测试结果
"origin": "null",
"readyState": 4,
"requestBuffer": null,
"requestCache": null,
"responseBuffer": [Buffer],
"responseCache": null,
"responseHeaders": [Object],
"responseTextCache": "Forbidden",
"responseURL": "http://localhost:3000/users/1",
"responseXMLCache": null,
"send": true,
"status": 403,
"statusText": "Forbidden",
"timeoutFn": null,
"timeoutId": 0,
"timeoutStart": 0,
"totalReceivedChunkSize": 9,
"uploadComplete": true,
"uploadListener": false,
},
},
"status": 403,
"statusText": "Forbidden",
}
18 | })
19 |
> 20 | test('Get User Info', async () => {
| ^
21 | await Ae.send(testData.getOneUser, {id: '1'})
22 | })
23 |
at Env.it (node_modules/jest-jasmine2/build/jasmine_async.js:102:24)
at Object.<anonymous> (test/index.test.js:20:1)
5.3. 接口返回响应体不符合预期测试结果
例如,resBodyStruct配置sessionId为number格式,但是返回的格式是字符串,将会如下格式的报错
TypeError: Expected a value of type `number` for `sessionId` but received `"123456"`.
60 | if (conf.resBodyStruct) {
61 | let Scheme = struct(conf.resBodyStruct)
> 62 | let result = Scheme.validate(res.data)
| ^
63 | if (result.length === 1) {
64 | reject(result[0])
65 | }
at Function.Struct.validate.value [as validate] (node_modules/superstruct/src/superstruct.js:78:17)
at src/index.js:62:29
6. Api
6.1. Aest.init(apiConfs)
初始化配置文件
const Ae = require('aester')
...
var conf = Ae.init(apiConfs)
6.2. Aest.send(apiConf, options)
发送请求。
options会与share合并,然后将对应变量渲染到请求模板中。
const Ae = require('aester')
...
Ae.send(testData.getOneUser, {id: '1'}
6.3. Aest.share(key, value)
设置共享变量
const Ae = require('aester')
...
var conf = Ae.share('token', '123123')
6.4. Aest.getShare()
获取所有共享变量
const Ae = require('aester')
...
var conf = Ae.getShare() // {token: '123123'}
7. 配置文件说明
key | 必须? | 说明 |
---|---|---|
$baseUrl | 是 | 请求baseUrl |
desc | 否 | 接口说明
req | 是 | 请求对象
req.method | 否 | 请求方法,默认get
req.path | 是 | 请求路径
req.headers | 是 | 默认为空对象,默认设置'content-type': 'application/json; charset=UTF-8'
resBodyStruct | 否 | 响应体格式校验对象
resBodyStruct字段说明
{
key: keyType
}
字段类型支持如下
- any: 任意
- number: 数字
- array: 数组
- string: 字符串
- boolean: 布尔值
- null: null
- undefined: undefined
- object: 对象类型
在字段类型后加上?
表示字段是否可选
如:
{
sessionId: 'string?' //sessionId是字符串,但是可以没有这个字段
}
更多字段类型验证参考:https://github.com/ianstormta...
8. 测试Aester
npm test
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。