22

我想测试请求返回中的错误。我在测试中使用了 nock,如何强制 Nock 引发错误?我想达到 100% 的测试覆盖率并且需要为此测试 err 分支

request('/foo', function(err, res) {
  if(err) console.log('boom!');
});

永远不要进入 if err 分支。即使 hit err 是一个有效的响应,我在测试中的 Nock 线看起来像这样

nock('http://localhost:3000').get('/foo').reply(400);

编辑: 感谢一些评论:

  • 我试图模拟请求中的错误。来自节点手册: https ://nodejs.org/api/http.html#http_http_request_options_callback 如果在请求期间遇到任何错误(可能是 DNS 解析、TCP 级别错误或实际 HTTP 解析错误),则会出现“错误”事件在返回的请求对象上发出
  • 错误代码(例如 4xx)没有定义 err 变量。我试图准确地模拟它,无论定义 err 变量并评估为 true 的错误
4

4 回答 4

38

使用回复错误。从文档:

    nock('http://www.google.com')
   .get('/cat-poems')
   .replyWithError('something awful happened');
于 2015-05-06T07:09:55.303 回答
5

When you initialise a http(s) request with request(url, callback), it returns an event emitter instance (along with some custom properties/methods).

As long as you can get your hands on this object (this might require some refactoring or perhaps it might not even be suitable for you) you can make this emitter to emit an error event, thus firing your callback with err being the error you emitted.

The following code snippet demonstrates this.

'use strict';

// Just importing the module
var request = require('request')
// google is now an event emitter that we can emit from!
  , google = request('http://google.com', function (err, res) {
      console.log(err) // Guess what this will be...?
    })

// In the next tick, make the emitter emit an error event
// which will trigger the above callback with err being
// our Error object.
process.nextTick(function () {
  google.emit('error', new Error('test'))
})

EDIT

The problem with this approach is that it, in most situations, requires a bit of refactoring. An alternative approach exploits the fact that Node's native modules are cached and reused across the whole application, thus we can modify the http module and Request will see our modifications. The trick is in monkey-patching the http.request() method and injecting our own bit of logic into it.

The following code snippet demonstrates this.

'use strict';

// Just importing the module
var request = require('request')
  , http = require('http')
  , httpRequest = http.request

// Monkey-patch the http.request method with
// our implementation
http.request = function (opts, cb) {
  console.log('ping');
  // Call the original implementation of http.request()
  var req = httpRequest(opts, cb)

  // In next tick, simulate an error in the http module
  process.nextTick(function () {
    req.emit('error', new Error('you shall not pass!'))
    // Prevent Request from waiting for
    // this request to finish
    req.removeAllListeners('response')
    // Properly close the current request
    req.end()
  })

  // We must return this value to keep it
  // consistent with original implementation
  return req
}

request('http://google.com', function (err) {
  console.log(err) // Guess what this will be...?
})

I suspect that Nock does something similar (replacing methods on the http module) so I recommend that you apply this monkey-patch after you have required (and perhaps also configured?) Nock.

Note that it will be your task to make sure you emit the error only when the correct URL is requested (inspecting the opts object) and to restore the original http.request() implementation so that future tests are not affected by your changes.

于 2015-01-04T12:04:51.310 回答
0

Posting an updated answer for using nock with request-promise.

Let's assume that your code calls request-promise like this:

require('request-promise')
  .get({
    url: 'https://google.com/'
  })
  .catch(res => {
    console.error(res);
  });

you can set up nock like this to simulate a 500 error:

nock('https://google.com')
  .get('/')
  .reply(500, 'FAILED!');

Your catch block would log a StatusCodeError object:

{
  name: 'StatusCodeError',
  statusCode: 500,
  message: '500 - "FAILED!"',
  error: 'FAILED!',
  options: {...},
  response: {
    body: 'FAILED!',
    ...
  }
}

Your test can then validate that error object.

于 2020-09-22T14:43:55.563 回答
-1

看起来您正在寻找 nock 请求的例外情况,这也许可以帮助您:

var nock = require('nock');
var google = nock('http://google.com')
               .get('/')
               .reply(200, 'Hello from Google!');

try{
  google.done();
}
catch (e) {
  console.log('boom! -> ' + e); // pass exception object to error handler
}
于 2014-12-31T10:53:00.400 回答