我正在为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
谢谢您的帮助。
答案 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()