Как проверить вывод журнала Hubot в тестовом скрипте - PullRequest
1 голос
/ 08 мая 2019

Я пишу тест для моего 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

Как я упоминал выше, я хотел бы проверить в своем тестовом скрипте, что HTTP-запрос был отправлен, утверждая, что в журнал будет включено сообщение 'Successfully sent HTTP POST request to Rails app'. Тем не менее, я не знаю, как получить доступ к журналу 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 голосов
/ 08 мая 2019

Я бы не советовал писать тесты в зависимости от логов.Журнал является побочным эффектом программы.Если вы измените вывод журнала, тесты не пройдут, хотя функциональность по-прежнему корректна.

Вместо этого вы должны использовать библиотеку для макета и проверки, был ли выполнен http-запрос.На самом деле выполнение запроса было бы побочным эффектом, и опять не должно выполняться в ваших тестах (что, если вы вызываете чрезмерную нагрузку на внешнюю службу из-за запуска тестов?

Вы уже используете nock библиотека для перехвата запроса. Также ее можно использовать для проверки выполнения запроса (см. документацию по ожиданиям из репозитория nock).

Вот пример использования requestScope.done() из nock в вашем тесте.

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


Версия обещания:

Что касается вашего комментария, здесьобещанная версия. Вам нужно передать .then функцию. Если вы передадите ее .then request.done(), ожидание request.done() будет выполнено немедленно, а его результат будет передан как обратный вызов обещания. Либо заключите его в другую функцию(см. ниже) или удалите скобки (.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()
...