测试嵌套在promise中的回调 [英] Testing a callback nested in a promise
问题描述
tl; dr 我需要测试是否成功加载Google电子表格后,我的方法向电子表格中添加了一行.
saveDataToGoogleSpreadSheet(conversationData){
return new Promise((resolve, reject) => {
Spreadsheet.load(this.getGoogleAPISettings(), (err, spreadsheet) => {
if (err) {
return reject(err);
}
return spreadsheet.receive((receivedError, rows, info) => {
if (receivedError) {
return reject(receivedError);
}
const rowData = this.getSpreadsheetRowData(conversationData, info.totalRows);
spreadsheet.add(rowData);
return spreadsheet.send(sendError => (sendError ? reject(sendError) : resolve()));
});
});
});
}
我测试了函数的第一种情况和第二种情况(前两个错误),但对于最后一个情况我却做不到,成功的情况是我们在电子表格中添加了一行.
I tested the case one and case two of the function (the two first errors) but I couldn't do it for the last one, the case of success where we an add a row to a spreadsheet.
我需要有关测试结构的帮助,或者有关如何进行测试的提示.
I need some help with the structure of the test, or a hint on how could my test be.
以前的测试是如何进行的
how the previous tests were made
it('should add a row to a Google Spreadsheet', (done) => {
nock('https://spreadsheets.google.com')
.post('/feeds/cells/1ZOd7Sysc-JNa-D5AHb7ZJkwBRMBGaeKpzIwEl7B8RbQ/1/private/full/batch')
.replyWithError({ message: 'abcde' });
api.saveDataToGoogleSpreadSheet({ data: 'some data' })
.then(() => done(new Error('should not have made the call')))
.catch((err) => {
expect(err).to.equal('Error Reading Spreadsheet');
done();
});
}).timeout(4000);
推荐答案
很难从您拥有的小代码中分辨出测试的问题,并且没有关于各种对象的含义以及它们如何产生的背景知识因此,我仅假设Spreadsheet
是通过所需的库创建的对象,除此之外,所有其他对象均由模块创建.即我假设您某处的线条类似于以下内容:
It is hard to tell what is the problem with the test from the little code you have, and no background on what the various objects are and how they come to be, so I will just assume that Spreadsheet
is an object that is created through a library you require, and other than that, all other objects are created by the module. i.e. I assume you somewhere have a line resembling something like this:
const Spreadsheet = require('some-google-docs-spreadsheet-lib');
这意味着一个问题是找出如何控制Spreadsheet
对象,以便我们了解其行为.
That means one problem is finding out how to control the Spreadsheet
object so we can stub out its behavior.
刚开始时,您可能会从这两个答案中获得一些通用代码和测试结构的良好指针,以便于测试,因为它们涵盖了两种最相关的技术:依赖注入和利用链接缝.
Just to start you out, you might get some good pointers on general code and test structure for easy testing from these two answers, as they cover the two most relevant techniques: dependency injection and exploiting link seams.
- Mocking Redis Constructor with Sinon
- How to test an ES6 class that needs jquery?
据我所知,您可能已经使用了其中一种技术,因为您已经说过能够测试这两种错误情况.但是,也许您还没有真正进行过单元测试,而是对服务进行了实际的网络调用(更多是集成测试)?无论如何,我仅假设我上面写的内容,并向您展示如何使用proxyquire
进行测试:
For all I know, you might already utilize one of these techniques, as you say you have been able to test the two error situations. But maybe you have not really been unit testing and done the actual network calls to the service instead (which is more of an integration test)? Anyway, I'll assume no more than what I wrote above and show you how to do the testing using proxyquire
:
const assert = require('assert');
const dummy = ()=> {};
const SpreadSheetStubLibrary = { load: dummy };
const MyClassToTest = proxyquire('../src/my-module', {
'some-google-docs-spreadsheet-lib': SpreadSheetStubLibrary
})
const config = {};
const conversationData = {};
let stubSetup;
let spreadsheet;
let myObj;
function setupStubs() {
stubSetup = stubSpreadsheetLoadFunction();
spreadsheet = stubSetup.spreadsheet;
SpreadSheetStubLibrary.load = stubSetup.load;
myObj = new MyClassToTest(config);
conversationData = {};
};
function createSpreadsheetStubObj(){
return {
receive: sinon.stub(),
add: sinon.stub(),
send: sinon.stub()
}
}
function stubSpreadsheetLoadFunction(){
const spreadsheet = createSpreadsheetStubObj();
return {
load: (settings, cb) => cb(null, spreadsheet),
spreadSheetStubObj: spreadsheet
};
}
it('should add a row to the spreadsheet on successful load', () => {
// Arrange
setupStubs();
const rowData = { foo: 1, bar: 2};
spreadsheet.receive.yields(); // calls any callback given
myObj.getSpreadsheetRowData = () => rowData; // see lines below
// if you want to use the real getSpreadsheetRowData, uncomment these lines
//const rows = []; // not used in the method?
//const info = { totalRows : 100 };
//spreadsheet.receive.yields(null, rows, info);
// Act
return myObj.saveDataToGoogleSpreadSheet(conversationData).then(()=>{
// Assert
assert(spreadsheet.add.calledOnce);
assert(spreadsheet.add.calledWith(rowData));
});
});
it('should add a row to the spreadsheet on successful load', () => {
// reuse the above
});
请参阅有关存根API的Sinon文档.
揭露:我是Sinon维护团队的成员.
Disclosure: I am part of the Sinon maintainer team.
这篇关于测试嵌套在promise中的回调的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!