测试嵌套在promise中的回调

时间:2017-06-12 12:57:19

标签: node.js unit-testing mocha sinon

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()));
      });
    });
  });
}

我测试了一个和第二个函数的案例(两个第一个错误),但我不能为最后一个做,成功的情况我们在电子表格中添加一行。

我需要一些测试结构方面的帮助,或者提示我的测试结果如何。

编辑:以前的测试是如何进行的

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);

1 个答案:

答案 0 :(得分:-1)

很难从你的小代码中判断测试的问题是什么,并且没有关于各种对象是什么以及它们是如何形成的背景,所以我将假设Spreadsheet是通过您需要的库创建的对象,除此之外,所有其他对象都由模块创建。即我假设你某处有一条类似于这样的线:

const Spreadsheet = require('some-google-docs-spreadsheet-lib');

这意味着一个问题是找出如何控制Spreadsheet对象,以便我们可以将其行为固定下来。

只是为了让你开始,你可能会得到一些关于通用代码和测试结构的好指示,以便从这两个答案中轻松进行测试,因为它们涵盖了两个最相关的技术:依赖注入和利用链接接缝。

就我所知,您可能已经使用了其中一种技术,正如您所说,您已经能够测试这两种错误情况。但也许您还没有真正进行过单元测试,而是完成了对服务的实际网络调用(这更像是集成测试)?无论如何,我只假设上面写的内容并告诉你如何使用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
});

请参阅Sinon docs for the stub API

披露:我是Sinon维护团队的一员。