在节点中测试失败的请求
我有一些如下所示的代码:
I have some code that looks like the following:
var request = require('request');
function Service(){
this._config = require('../path/to/config.json');
}
Service.prototype.doThing = function(){
return new Promise(function(resolve, reject){
request.post(url, {payload}, function(error, response, body){
//handle response
resolve(true);
}).on('error', function(err){
//handle errors
resolve(false);
});
});
}
我正在尝试测试错误运行的块,但由于承诺而遇到困难.我使用 mocha 进行测试运行,使用 sinon 进行存根.我能够存根请求,以便我可以计算调用 on 方法的次数,但包含的 Promise 永远不会解析.
I'm trying to test the block that runs on error, but having difficulty because of the promise. I'm using mocha for test running and sinon for stubbing. I'm able to stub request so that I can count the number of times the on method is called, but the containing Promise never resolves.
有一些包可以与 sinon 一起处理承诺(我尝试过 sinon-as-promised 和 sinon-stub-promise),但我必须存根整个 doThing 方法才能正确解析.我将不胜感激任何有关测试此代码或可能更易于测试的替代代码结构的正确方法的输入.
There are some packages that work with sinon to handle promises (I've tried sinon-as-promised and sinon-stub-promise), but I have to stub the entire doThing method in order for it to resolve properly. I would appreciate any input on the propper way to test this code or alternate code structures that may be easier to test.
有问题的测试(挂起等待 doThing 承诺返回)如下:
The test in question (that hangs waiting for the doThing promise to return) is below:
context('when the server is unavailable', function(){
beforeEach(function() {
var onStub = sinon.stub();
requestStub = {post: function(){ return {on: onStub}}};
Service = proxyquire('path/to/service', {request: requestStub});
service = new Service();
});
it('should not set the auth key', function(){
return service.doThing().then(function(x){
return assert(onStub.calledOnce);
});
});
});
谢谢!
总结一下显而易见的问题,你在这里的问题是你没有控制 request
对象,或者更确切地说是它的响应发布代码>方法.如果您可以控制,您将能够在您的 doThing
方法中测试所有不同的代码路径.
To sum up the obvious, your problem here is that you do not control the request
object, or rather the response from its post
method. If you can control that you will be able to test all the different code paths in your doThing
method.
您有三种可能来控制来自 request
的响应:
You have three possibilities for controlling the response from request
:
- 剔除网络层(使用类似Nock) 这样您就可以控制 HTTP 层将哪些内容移交给
request
库. - 使用依赖注入注入一个可以代替
request.post
的存根(需要修改代码) - 使用链接接缝,将
require()
调用返回的对象替换为您控制的存根对象.这当然是你所做的.
- Stub out the network layer (using something like Nock) so you can control what the HTTP layer is handing over to the
request
library. - Use dependency injection to inject a stub that can be used in place of
request.post
(will require a code modification) - Use a link seam to that will substitute the object returned from
require()
calls with a stub object you control. This is of course what you have done.
就我个人而言,我会选择选项 2,因为它不需要额外的框架,易于推理且易于实现.您可以参考这个非常详细的示例,但您的情况所需的代码很少.
Personally, I would have gone for option 2 since that requires no extra framework, is easy to reason about and is easy to implement. You can refer to this quite elaborate example, but the code needed in your case is minimal.
无论如何,既然您选择了选项 3,我不妨沿着这条路线走下去 :-) 问题在于您如何消除 post
方法.会不会打电话给你的回电?
Anyway, since you have chosen option 3 I might as well go down that route :-) The problem is how you stubbed out the post
method. Have will that ever call your callback?
我会将 post
存根更改为如下所示:
I would change the post
stub to something like this:
post: (url, options, cb) => {
cb(null, null, null); // will resolve your promise in the module
return { on: onStub };
}
当然,如果您稍后需要对值执行某些操作,则传递到您的回调中的 null
可以是其他内容.
Of course, the null
s passed into your callback can be something else should you need to do something with the values later on.