编写自己的newman reporter

1. newman?report?

1.1 newman是什么

newman时一款基于Node.js开发的可以运行postman的工具,使用Newman可以直接从命令行运行postman集合。更多介绍可以参看这里

1.2 reporter是什么

reporter决定了newman输出的形式,不同的repoter以不同的形式输出newman的执行结果。如果自带的reporter和第三方reporter都不能满足自己需要,就要DIY自己的reporter了。

2. 如何编写自己的repoter

对于如何编写自己的report, 文档上写的非常简略。

https://www.npmjs.com/package/newman#creating-your-own-reporter

只是说了repoter是以node模块的形式存在,模块该以什么形式命名,如何打包。那么具体的模块内部逻辑该如何写呢?

2.1 思路

起先我也不知如何入手,读了两个第三方reporter后,发现思路是这样的:
newman在执行过程中提供了各种事件的回调,比如集合开始执行、test执行前、test执行后、集合执行结束等等。你只需要在适合的事件上注册自己的回调函数,在函中记下自己要的信息。在集合执行结束后输出即可。

2.2 事件

newman提供的事件在文档上列的比较清楚

https://www.npmjs.com/package/newman#newmanrunevents

比较常用的如下:

  • start: 整个集合开始运行
  • beforeItem:单个条目(item)开始运行前。
    一个条目是指prerequest->request->test的整个过程。
  • item: 单个条目运行结束
  • beforeRequest:发送http请求之前。注意,是任何http请求。我们不但在request中会发http请求。在prerequest, tests中也可能会发送http请求。
  • request:请求结束拿到响应后
  • beforeTest:测试脚本开始前
  • test:测试脚本结束后
  • assertion:每个test结束后。注意是一个test,每个request可以包含多个test。
    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-gsK7oxNu-1588846918929)(http://dl.qqpy.sogou.com/business/20200426/765a6ee830a9428d918f55c9c0b1517f.png)]

上例中,assertion会被触发3次。

  • beforeDone:整个执行(run)完成前

所有的事件回调函数可以接收两个参数:

  • err: 出错信息
  • info: 执行信息。每个事件的执行信息包括哪些内容是不同的,文档中没有写,只能自己console.log输出看一下了。
    比如, assertion的info包括了如下诸多信息
{
  cursor: {
    position: 0,
    ... ...
    ref: '085d9877-fdb0-4097-a9d4-88092bfd3e21',
    httpRequestId: '456d2ac5-4b54-4bee-90cb-21609c70b186',
    scriptId: '144be8cb-482b-4c09-be43-5fb93ad58c9e',
    execution: 'f58760ef-64f1-47fb-b5fd-1b0e6acc17f7'
  },
  //当前test的名子
  assertion: 'http code is 200',
  skipped: false,
  //test错误信息, 当test中有断言出错时,会有此项
  error: {
    name: 'AssertionError',
    message: 'expected response to have status code 302 but got 200',
    showDiff: true,
    actual: 200,
    expected: 302,
    stack: 'AssertionError: expected response to have status code 302 but got 200\n' +
      '    at eval (eval at exec (evalmachine.<anonymous>:13180:2548), <anonymous>:3:25)\n' +
      '    at Postman.n.test (evalmachine.<anonymous>:81:386)\n' +
      '    at Object.eval (eval at exec (evalmachine.<anonymous>:13180:2548), <anonymous>:2:4)\n' + ... ...
  },
  item: PostmanItem {
    ... ...
  }
}

3. 一个例子

单看上面的内容可能你还有些迷糊,那么让我们看来一个实际的例子。

3.1 代码注释

这是一个第三方的reporter, 以csv形式输出结果,取自

https://github.com/matt-ball/newman-reporter-csv/blob/master/index.js

我给它加一些注释,希望对理解如何编写reporter有帮助。

let log
const logs = []
//定义自己的记录格式字段(csv的表头),输出结果时过滤用
const columns = [
  'iteration',
  'collectionName',
  'requestName',
  'method',
  'url',
  'status',
  'code',
  'responseTime',
  'responseSize',
  'executed',
  'failed',
  'skipped'
]

const CSV = {
  stringify: (str) => {
    return `"${str.replace(/"/g, '""')}"`
  }
}

/**
 * Reporter that outputs basic logs to CSV (default: newman-run-report.csv).
 *
 * @param {Object} newman - The collection run object, with event hooks for reporting run details.
 * @param {Object} options - A set of collection run options.
 * @param {String} options.export - The path to which the summary object must be written.
 * @returns {*}
 */
module.exports = function newmanCSVReporter (newman, options) {
  //每个item执行前清空log
  newman.on('beforeItem', (err, e) => {
    if (err) return

    log = {}
  })

  //请求之前记录集合名,迭代次,item名,url等信息
  newman.on('beforeRequest', (err, e) => {
    if (err) return
    const { cursor, item, request } = e

    Object.assign(log, {
      collectionName: newman.summary.collection.name,
      iteration: cursor.iteration + 1,
      requestName: item.name,
      method: request.method,
      url: request.url.toString()
    })
  })

  //请求后记录http返回码,请求时间,请求大小等信息
  newman.on('request', (err, e) => {
    if (err) return
    const { status, code, responseTime, responseSize } = e.response
    Object.assign(log, { status, code, responseTime, responseSize })
  })

  //每个test后记录执行情况
  newman.on('assertion', (err, e) => {
    const { assertion } = e
    const key = err ? 'failed' : e.skipped ? 'skipped' : 'executed'

    log[key] = log[key] || []
    log[key].push(assertion)
  })
    
  //每个item执行完,收集整条log
  newman.on('item', (err, e) => {
    if (err) return

    logs.push(log)
  })

  //run执行完之前
  newman.on('beforeDone', (err, e) => {
    if (err) return
    
    newman.exports.push({
      //repoter名子
      name: 'csv-reporter',
      //默认文件名形式
      default: 'newman-run-report.csv',
      //输出路径
      path: options.export,
      //输出内容
      content: getResults()
    })

    console.log('CSV write complete!')
  })
}

//处理logs中的每条log, 将其转为csv格式
function getResults () {
  const results = logs.map((log) => {
    let row = []

    Object.keys(log).forEach((key) => {
      const val = log[key]
      const index = columns.indexOf(key)
      const rowValue = Array.isArray(val)
        ? val.join(', ')
        : String(val)

      row[index] = CSV.stringify(rowValue)
    })

    return row.join(',')
  })

  results.unshift(columns.join(','))

  return results.join('\n')
}

3.2 说明

  1. 回调中提供的信息(上述代码中的e)所包括的内容,从上面的例子中可以窺其一斑。
  2. 上面的代码其实是有bug的。我们知道对于一个item来说,其执行顺序为:
pre-request脚本
发送请求, 收到响应
test脚本

所以,如果test脚本中也有http请求时,同样会触发beforeRequest, request两个事件。这样就会覆盖我们希望记录的真实请求的相应内容。改正的思路也比较简单,test部分的事件发生顺序为:

beforeTest
beforeRequest
request
test

所以,我们只需要在beforeTest中设置测试标识,在beforeRequest,request中进行检测,如果是测试过程则跳过信息记录。最后在test中清理测试标识即可。核心思想代码如下:

module.exports = function newmanCSVReporter (newman, options) {
    //全局标记
    var inTest = false;
  
    newman.on('beforeTest', (err, e)=>{
        //测试开始前设置标识
	    inTest = true;
    });

    newman.on('test', (err, e)=>{
        //测试结后清理标识
	    inTest = false;
    });

    newman.on('beforeRequest', (err, e) => {
        if (err || inTest) return
        
        //之前逻辑不变
    })

    newman.on('request', (err, e) => {
        if (err || inTest) return
    
        //之前逻辑不变
        ... ...
    })

4. 调试

比如你写了一段3.1中的代码,想要调试,如何进行呢?

  1. 安装newman
  2. 安装reporter: newman-reporter-csv
  3. 找到你的node_modules目录
node_modules/newman-reporter-csv/index.js

上面就是执行使用csv reporter时实际执行的代码。使用下面的方式执行newman, 可以让你对index.js的改动立刻生效。

node_modules/.bin/newman run test.postman_collection.json -r csv
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值