如何在测试脚本中检查Hubot日志输出

时间:2019-05-08 07:10:40

标签: testing logging coffeescript mocha hubot

我正在为Hubot(充当Slack机器人)编写测试。由某些Slack消息触发,该机器人将HTTP POST请求发送到单独的Rails应用。如何在测试脚本中检查HTTP请求已发送?我的猜测是我应该检查robot.logger的内容(请告诉我是否有更好的方法)-但是,如果是这样,我如何访问测试中的日志?

Hubot脚本(基本上,它会通知Rails应用有关正在离开办公室休息的用户的信息):

module.exports = (robot) ->
  robot.respond /off to lunch/i, (res) ->
    res.reply('Later alligator')
    robot.logger.info "This user is going on lunch break: #{res.message.user.id}"

    data = JSON.stringify({
      slack_user_id: res.message.user.id
    })
    robot.http(process.env.RAILS_APP_URL + '/break')
      .header('Content-Type', 'application/json')
      .post(data) (err, resp, body) ->
        if err
          robot.logger.info "Encountered an error. #{err}"
          res.reply('Sorry, there was an error recording your break time')
        else
          robot.logger.info 'Successfully sent HTTP POST request to Rails app'

执行此脚本时的日志输出:

INFO This user is going on lunch break: [SLACK_USER_ID]
INFO Successfully sent HTTP POST request to Rails app

如上所述,我想通过断言日志将包含消息'Successfully sent HTTP POST request to Rails app'来检查测试脚本是否发送了HTTP请求。但是,在测试中,我不知道如何访问Hubot的日志。我认为这可能与process.stdout有关,因为该机器人会记录到stdout,但我无法使其正常工作。

测试脚本:

Helper = require('hubot-test-helper')
helper = new Helper('../scripts/break-start.coffee')
request = require('request')
expect = require('chai').expect
nock = require('nock')

describe 'bot responds to user message and sends ', ->
  beforeEach ->
    # Set up the room before running the test.
    @room = helper.createRoom()

    # Set up a request interceptor.
    nock(process.env.RAILS_APP_URL)
      .post('/break', { slack_user_id: 'bob' })
      .reply(200)

  afterEach ->
    # Tear down the room after the test to free up the listener.
    @room.destroy()

  context 'user sends lunch message', ->
    beforeEach ->
      @room.user.say('bob', '@hubot Off to lunch')

    it 'responds to users who are off to lunch', ->
      expect(@room.messages).to.eql [
        ['bob', '@hubot Off to lunch']
        ['hubot', '@bob Later alligator']
      # I want to do something like this:
      # expect(robot.log).include('Successfully sent HTTP POST request to Rails app')

当然,当我运行测试时,可以在控制台日志中看到正在发送HTTP请求,但是我也想断言它,以便在未发送请求时测试失败。

执行测试时的日志输出:

INFO This user is going on lunch break: bob
✓ responds to users who are off to lunch
INFO Successfully sent HTTP POST request to Rails app

谢谢您的帮助。

1 个答案:

答案 0 :(得分:0)

我不建议根据日志来编写测试。日志是程序的副作用。如果更改日志输出,即使功能仍然正确,测试也将失败。

相反,您应该使用库来模拟并检查是否已执行http请求。实际上,发出请求是一种副作用,并且不应在测试中再次进行(如果由于测试运行而导致外部服务上的负载过大怎么办?

您已经在使用nock库来捕获请求。它也可以用来检查是否发出了请求(请参阅nock回购中的expectations docs)。

以下是在测试中使用nock的requestScope.done()的示例。

it 'sends the break request to the rails server', ->
  # capture the request to the rails app
  railsRequest = nock(process.env.RAILS_APP_URL)
    .post('/break', { slack_user_id: 'bob' })
    .reply(200)
  # make the request and wait for it to be completed
  await @room.user.say('bob', '@hubot Off to lunch')
  # check that the request was made
  railsRequest.done()

我正在使用await来确保应该进行请求的函数调用在测试之前完成。如果您不熟悉await,则可以通过railsRequest.done()调用将支票(.then())移到@room.user.say(...) Promise处理程序中。


承诺版本:

关于您的评论,这是约定的版本。您需要传递.then一个函数。如果您将其传递给.then request.done(),则request.done()期望将立即执行,其结果将作为promise回调传递。将其包装在另一个函数中(请参见下文)或删除括号(.then request.done)。但是要注意第二种选择。如果您的诺言返回一个值,它将被传递给回调。由于它来自库,因此可能会导致意外行为-这就是为什么我建议第一个选项的原因:

it 'sends the break request to the rails server', ->
  # capture the request to the rails app
  railsRequest = nock(process.env.RAILS_APP_URL)
    .post('/break', { slack_user_id: 'bob' })
    .reply(200)
  # make the request and wait for it to be completed
  @room.user.say('bob', '@hubot Off to lunch').then ->
    # check that the request was made
    railsRequest.done()