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

How to check Hubot log output in test script

我正在为我的 Hubot(充当 Slack 机器人)编写测试。由某些 Slack 消息触发,该机器人向单独的 Rails 应用程序发送 HTTP POST 请求。如何检查我的测试脚本是否已发送 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 有关,因为机器人记录到标准输出,但我无法让它工作。

测试脚本:

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

提前感谢您的帮助。

我不建议根据日志编写测试。日志是程序的一个side-effect。如果更改日志输出,测试将失败,即使功能仍然正确。

相反,您应该使用一个库来模拟并检查是否执行了 http 请求。实际上发出请求将是 side-effect,并且在您的测试中也不应该这样做(如果由于测试 运行 而导致外部服务负载过大怎么办?

您已经在使用 nock 库来捕获请求。它还可用于检查是否已发出请求(请参阅 nock repo 中的 expectations docs)。

这是一个在你的测试中使用箭尾的 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()) 移动到 @room.user.say(...) 调用的 .then() 承诺处理程序中。


承诺版本:

关于您的评论,这里是承诺的版本。您需要传递 .then 一个函数。如果你传递它 .then request.done() 那么 request.done() 期望将立即执行并且它的结果将作为承诺回调传递。将其包装在另一个函数中(见下文)或删除括号 (.then request.done)。但要小心第二种选择。如果你承诺 returns 一个值,这将被传递给回调。由于它来自图书馆,这可能会导致意外行为 - 这就是我建议第一个选项的原因:

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()