Aest 功能强大的NodeJS Restful 接口测试工具

2018-08-10 admin

项目地址: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

原文链接:https://segmentfault.com/a/1190000015958808

本站文章除注明转载外,均为本站原创或编译。欢迎任何形式的转载,但请务必注明出处。

转载请注明:文章转载自 JavaScript中文网 [https://www.javascriptcn.com]

本文地址:https://www.javascriptcn.com/read-37688.html

文章标题:Aest 功能强大的NodeJS Restful 接口测试工具

相关文章
从2014年的发展来展望JS的未来将会如何
&lt;font face=&quot;寰�杞�闆呴粦, Arial, sans-serif &quot;&gt;2014骞达紝杞�浠惰�屼笟鍙戝睍杩呴€燂紝鍚勭�嶈��瑷€灞傚嚭涓嶇┓锛屼互婊¤冻鐢ㄦ埛涓嶆柇鍙樺寲鐨勯渶姹傘€傝繖浜涜��...
2015-11-12
12个你未必知道的CSS小知识
虽然CSS并不是一种很复杂的技术,但就算你是一个使用CSS多年的高手,仍然会有很多CSS用法/属性/属性值你从来没使用过,甚至从来没听说过。 1.CSS的color属性并非只能用于文本显示 对于CSS的color属性,相信所有Web开发人员...
2015-11-12
ajax为什么令人惊异?ajax的优缺点
使用Ajax的最大优点,就是能在不更新整个页面的前提下维护数据。这使得Web应用程序更为迅捷地回应用户动作,并避免了在网络上发送那些没有改变的信息。 Ajax不需要任何浏览器插件,但需要用户允许JavaScript在浏览器上执行。就像DHT...
2015-11-12
HTML5的5个不错的开发工具推荐
HTML5规范终于在今年正式定稿,对于从事多年HTML5开发的人员来说绝对是一个重大新闻。数字天堂董事长,DCloud CEO王安也发表了文章,从开发者和用户两个角度分析了HTML对两个人群的优势。其实,关于HTML5的开发工具,我们以往的...
2015-11-12
JavaScript教程:JS中的原型
Keith Peters 几年前发表的一篇博文,关于学习没有“new”的世界,其中解释了使用原型继承代替构造函数。两者都是纯粹的原型编码。 标准方法(The Standard Way) 一直以来,我们学习的在 JavaScript 里创建对...
2015-11-12
NodeJS参考手册pdf版
下载地址:Nodejs参考手册PDF版下载 ...
2015-11-12
AJAX的浏览器支持
AJAX 的要点是 XMLHttpRequest 对象。 不同的浏览器创建 XMLHttpRequest 对象的方法是有差异的。 IE 浏览器使用 ActiveXObject,而其他的浏览器使用名为 XMLHttpRequest 的 Jav...
2015-11-12
Riot.js:不足1KB的MVP客户端框架
Riot.js是一款MVP(模型-视图-呈现)开源客户端框架,其最大的特点就是体积非常小,不足1KB,虽然体积小,但它可以帮助用户构建大规模的Web应用程序。 Riot.js是由Moot公司开发,目前最新版本为v0.9.2,遵循MIT开源许...
2016-03-11
JavaScript的组成
一个完整的JavaScript由3个部分组成:核心(ECMAScript) 文档对象模型(DOM) 浏览器对象模型(BOM) ECMAScript 描述了该语言的语法和基本对象 ; DOM 描述了处理网页内容的方法和接口 ; BOM 描...
2015-11-12
typeof、instanceof和contructor的区别
typeof:以字符串的形式返回变量的原始类型,typeof在两种情况下会返回&quot;undefined&quot;:一个变量没有被声明的时候,和一个变量的值是undefined的时候,注意,typeof null也会返回object,...
2015-11-12
回到顶部