使用 Sinon.js 测试承诺/异步流
Testing Promises/Async flow with Sinon.js
我在测试一个函数的返回值时遇到问题,该函数在执行之前等待承诺被解析。
Javascript Method (serviceClient._getProduct 返回 jQuery ajax promise 对象)
serviceClient.getProductName = function(id, storeId) {
$.when(self._getProduct(id)).done(function(data) {
return data.name;
});
};
测试代码
before(function() {
serviceClient.sampleResponse = fixture.load('product_response.json')[0];
$.ajaxStub = sinon.stub($, 'ajax').returns(new $.Deferred().resolve(serviceClient.sampleResponse));
});
describe('.getProductName', function() {
it('should return the product name', function() {
var name = serviceClient.getProductName(serviceClient.sampleResponse.id);
$.when($.ajaxStub.returnValue).done(function() {
expect(name).to.equal(serviceClient.sampleResponse.name);
});
});
});
当我单步执行调用堆栈时,它似乎正在正确执行(在实际 js 文件中的 promise 回调内执行步骤,然后步入测试承诺回调以断言),但是测试中的名称变量仍然以未定义的形式返回。任何反馈将不胜感激。
您正在尝试在 serviceClient.getProductName
中同步返回data.name
,这无法完成,因为它依赖于异步 ajax 请求。
你在回调中执行return data.name;
操作,这不会得到预期的结果:如果你同步返回一些东西,那么return
句子应该在该闭包之外的范围内。
简单来说:如果有什么东西可以退回,那就是延期或承诺。它应该是这样的:
serviceClient.getProductName = function(id, storeId) {
var deferredName = $.Deferred();
$.when(self._getProduct(id)).done(function(data) {
deferredName.resolve(data.name);
}).fail(function(jqXHR, textStatus, error) {
deferredName.reject(error);
});
return deferredName.promise();
// Or, if needed (I don't think so, it's resolved and rejected here)
// return deferredName;
};
然后,在您的测试中:
before(function() {
serviceClient.sampleResponse = fixture.load('product_response.json')[0];
$.ajaxStub = sinon.stub($, 'ajax').returns(new $.Deferred().resolve(serviceClient.sampleResponse));
});
describe('.getProductName', function() {
it('should return the product name', function() {
serviceClient.getProductName(serviceClient.sampleResponse.id)
.done(function(name) {
expect(name).to.equal(serviceClient.sampleResponse.name);
});
});
});
撇开代码不谈,概念上的错误是,当该函数异步获取产品时,您可以从getProductName
同步返回name
(在解决延迟之前,它无法访问其名称)。
注意:您可以使用 then
来实现getProductName
,它返回一个 Promise(它是延迟的子集,但您通常可以侥幸逃脱,代码看起来更清晰):
serviceClient.getProductName = function(id, storeId) {
return $.when(self._getProduct(id)).then(function(data) {
return data.name;
});
};
要删除它,也是不必要的$.when(...)
,您也可以从_getProduct
返回一个承诺(如果您有延迟,获得承诺就像调用deferred.promise()
一样简单)。
相关文章:
- 为什么同步睡眠功能没有被承诺内异步化
- 如何按照承诺使用mocha/chai/chai测试ES7异步函数
- Node JS异步承诺.所有问题
- 将异步工作流更改为承诺(蓝鸟)
- JQuery 承诺异步对话
- WinJS,从可能是异步的函数返回一个承诺,也可能不是异步的
- 同步异步创建的承诺
- 当我在异步操作Redux上开始单元测试时,没有定义错误承诺
- 使我的异步代码与setTimeout同步.我需要承诺吗
- 异步角度承诺和变量初始化
- 如何在节点中使用承诺一次并行异步多个请求
- 使用链式 Q 承诺异步加载的局部变量
- JavaScript 异步编程:承诺与生成器
- Ember:解决复杂的异步承诺
- 异步承诺中未处理的承诺拒绝
- ES6异步承诺
- 非异步承诺回调
- 使用Bluebird进行异步承诺处理
- 异步承诺失败时首选throw或reject
- Angular: Switch语句中的异步承诺