【问题标题】:How to check Hubot log output in test script如何在测试脚本中检查 Hubot 日志输出
【发布时间】:2019-09-25 20:50:32
【问题描述】:

我正在为我的 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 有关,因为机器人记录到标准输出,但我无法让它工作。

测试脚本:

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

提前感谢您的帮助。

【问题讨论】:

    标签: testing logging coffeescript mocha.js hubot


    【解决方案1】:

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

    相反,您应该使用库来模拟并检查是否执行了 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()) 移到 @room.user.say(...) 调用上的 .then() 承诺处理程序中。


    承诺版本:

    关于您的评论,这是承诺的版本。您需要传递.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()
    

    【讨论】:

    • 感谢您的回复。我认为使用await 需要一个带有关键字async 的函数。由于没有async,您建议的代码返回ReferenceError: await is not defined。有没有办法在这里使用async/await
    • 我也尝试使用.then 承诺,这很有效:@room.user.say('bob', '@hubot Off to lunch').then(@railsRequest.isDone())。但是如果我将isDone() 换成done(),我会得到一个AssertionErrorMocks not yet satisfied。不知道为什么即使我阅读了docs,因为区别似乎是“所有指定的调用与单个调用”,但这里只有一个模拟开始。很抱歉有多个问题,再次感谢!
    猜你喜欢
    • 2019-09-24
    • 2017-10-22
    • 2022-07-06
    • 2016-12-23
    • 2022-11-24
    • 1970-01-01
    • 2018-12-06
    • 2021-12-11
    • 1970-01-01
    相关资源
    最近更新 更多