如何使用 Nock 测试请求中的错误?
Posted
技术标签:
【中文标题】如何使用 Nock 测试请求中的错误?【英文标题】:How to test error in request with Nock? 【发布时间】:2015-02-26 19:48:24 【问题描述】:我想测试请求返回中的错误。我在测试中使用了 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);
编辑: 感谢一些 cmets:
我试图模拟请求中的错误。从节点手册: https://nodejs.org/api/http.html#http_http_request_options_callback 如果在请求期间遇到任何错误(可能是 DNS 解析、TCP 级别错误或实际的 HTTP 解析错误),则在返回的请求对象上会发出“错误”事件 错误代码(例如 4xx)未定义 err 变量。我试图准确地模拟这一点,无论定义 err 变量并评估为 true 的错误【问题讨论】:
你就不能提出一个错误的要求吗?例如将 url 设置为''
或 undefined
。
@agconti with nock 你模拟了服务器响应,我试图强制一个 http 错误。来自节点手册 (nodejs.org/api/http.html#http_http_request_options_callback) 如果在请求期间遇到任何错误(可能是 DNS 解析、TCP 级别错误或实际 HTTP 解析错误),则会在返回的请求对象上发出“错误”事件。
这种行为与模型无关。您是否尝试过让它回复 HTTP 错误消息?
@E_net4 是的,res.statusCode 中有一条 http 错误消息,它不会生成 javascript 错误
好吧,别介意我最后的评论。 HTTP 错误消息不会触发这种错误。但请说明您要模拟的错误类型。
【参考方案1】:
使用replyWithError。 来自文档:
nock('http://www.google.com')
.get('/cat-poems')
.replyWithError('something awful happened');
【讨论】:
不错的方法,但可能会受到限制,因为它会在请求对象上发出错误,而不是响应。但是如果你想得到错误代码的响应,你可以使用.get('/foo') .reply(function (url, body, cb) cb(null, [400, ]); );
【参考方案2】:
当您使用 request(url, callback)
初始化一个 http(s) 请求时,它会返回一个事件发射器实例(以及一些自定义属性/方法)。
只要你能得到这个对象(这可能需要一些重构,或者它甚至可能不适合你)你可以让这个发射器发出一个error
事件,从而用@触发你的回调987654323@ 是您发出的错误。
以下代码 sn-p 演示了这一点。
'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'))
)
编辑
这种方法的问题在于,在大多数情况下,它需要进行一些重构。另一种方法利用 Node 的本地模块在整个应用程序中缓存和重用的事实,因此我们可以修改 http
模块,Request 将看到我们的修改。诀窍在于猴子修补http.request()
方法并将我们自己的逻辑注入其中。
以下代码 sn-p 演示了这一点。
'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...?
)
我怀疑 Nock 做了类似的事情(替换 http 模块上的方法),所以我建议您在之后应用这个猴子补丁你已经需要(也许还配置了?)Nock。
请注意,您的任务是确保仅在请求正确的 URL 时发出错误(检查 opts
对象)并恢复原始的 http.request()
实现,以便将来的测试不受您的影响变化。
【讨论】:
非常聪明的实现@RobertRossman。我唯一的问题是重构不容易允许这样做。有多个请求,我需要测试所有请求。从测试中很难访问这个发射器实例。这是因为我使用的是 Nock,它会模拟匹配特定 url 的 http 请求 我不确定你是否还能做更多...我脑海中突然出现了一个选项 - 我稍后会更新这个答案。 已更新 - 请参阅 EDIT 部分。 感谢您的更新。我想这是我目前唯一能做的。就像创建我自己的诺克一样,但仅适用于特殊情况。如果是唯一的选择,我会尝试:)【参考方案3】:发布使用nock
和request-promise
的更新答案。
假设您的代码像这样调用request-promise
:
require('request-promise')
.get(
url: 'https://google.com/'
)
.catch(res =>
console.error(res);
);
你可以这样设置nock
来模拟500错误:
nock('https://google.com')
.get('/')
.reply(500, 'FAILED!');
您的 catch
块将记录一个 StatusCodeError
对象:
name: 'StatusCodeError',
statusCode: 500,
message: '500 - "FAILED!"',
error: 'FAILED!',
options: ...,
response:
body: 'FAILED!',
...
然后您的测试可以验证该错误对象。
【讨论】:
【参考方案4】:看起来您正在寻找关于 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
【讨论】:
谢谢我正在尝试实现 100% 的测试覆盖率,但我需要一种方法来触发(引发)该错误,问题是 nock 只有在没有该 url 的映射时才会失败以上是关于如何使用 Nock 测试请求中的错误?的主要内容,如果未能解决你的问题,请参考以下文章