AssertError: expeced to be called once but was called 0 times

sha*_*dow 5 unit-testing node.js sinon

I am using nodejs and sinon.

目前,当我运行我的应用程序(即 UpdateTask 类)时,它工作正常,甚至出现错误。

然而,当我开始进行单元测试时,我遇到了以下问题。

AssertError: expected updateBook to be called once but was called 0 times
Run Code Online (Sandbox Code Playgroud)

我不明白为什么它应该被调用 0 次,而它应该被调用一次。

我的代码中有什么错误吗?

更新任务类:

function updateInfo() {

    let updateCountParams = [];
    let updateParams = [];

    let idsToUpdateList = null;

    tempTable.getBookForUpdateCount(updateCountParams, function (results) {

        if (results[0].RECCOUNT > 0) {

            tempTable.getBookForUpdate(updateParams, function (results) {

                idsToUpdateList = results;

                for (var i = 0; i < idsToUpdateList.length; i++) {
                    let id = idsToUpdateList[i].id;

                    let param = [];
                    param.push(id);

                    let request = api.sendRequest(id);

                    // Invoke asynchronous call
                    request
                        .buffer(true)
                        .end(function (err, res) {

                            if (err) {

                                tempTable.updateBook(param, function (updateBookResult) {

                                });

                                return console.error(err.status + " - " + err.message);
                            }

                            let data = {
                                body: res.body,
                                text: res.text
                            };

                            let bkData = data.text;

                            if (bkData == undefined || bkData == null) {

                                tempTable.updateBook(param, function (updateBookResult) {

                                });

                                return console.error("DATA NOT FOUND".red);
                            }

                            //success flow business logic here
                            ...


                        }); //end asynchronous call
                }
            });
        }
        else {
            //no record to be processed.
            return;
        }
    });
}
Run Code Online (Sandbox Code Playgroud)

测试用例:

    describe('Update Task', () => { 
    beforeEach(() => {

    });

    afterEach(() => {
        sinon.restore();
    });


    it('3. API Call - Errror: 404 - Not found', (done) => {

        let getTempTableForUpdateCountSpy = sinon.stub(TempTableDao, "getBookForUpdateCount").yields(jsonResult.count.success.result);
        let getTempTableForUpdateSpy = sinon.stub(TempTableDao, "getBookForUpdate").yields(jsonResult.single.failure.result);
        let getTempTableUpdateSpy = sinon.stub(TempTableDao, "updateBook");

        let test = nock('https://test.api.com/id')
                .get('/ID125125/')
                .reply(404, {

                 });

        updateTask.updateInfo();

        sinon.assert.calledOnce(getTempTableForUpdateCountSpy);
        sinon.assert.calledOnce(getTempTableForUpdateSpy);
        test.interceptors[0].statusCode.should.be.equal(404);
        sinon.assert.calledOnce(getTempTableUpdateSpy);

        done();
    });
Run Code Online (Sandbox Code Playgroud)

Bri*_*ams 4

问题

tempTable.updateBook在回调期间调用,该回调在运行时尚未运行sinon.assert.calledOnce(getTempTableUpdateSpy);并失败。


解决方案

确保调用的回调tempTable.updateBook在断言之前有机会运行。

当使用 Promise 时,这要容易得多,可以在测试中返回并等待 Promise。这种情况比较棘手,因为存在回调并且没有干净的方法来返回可以等待的内容。

需要注意的重要一点是,测试将保持活动状态,直到超时或被done调用。

在这种情况下,它看起来updateBook是代码中最后发生的事情,也是需要测试的最后一件事。对于这样的场景,可以为存根和断言提供模拟实现,然后done在模拟实现中调用。

这是一个简化的示例:

import * as sinon from 'sinon';

const tempTable = {
  updateBook: () => {}
};

const updateInfo = () => {
  setTimeout(() => { tempTable.updateBook(); }, 0);  // simulate an asynchronous callback
}

test('updateInfo', (done) => {
  const spy = sinon.stub(tempTable, 'updateBook');
  spy.callsFake(() => {
    sinon.assert.calledOnce(spy);  // SUCCESS
    done();
  });
  updateInfo();
});
Run Code Online (Sandbox Code Playgroud)

在你的情况下,你可以这样做:

it('3. API Call - Errror: 404 - Not found', (done) => {

  let getTempTableForUpdateCountSpy = sinon.stub(TempTableDao, "getBookForUpdateCount").yields(jsonResult.count.success.result);
  let getTempTableForUpdateSpy = sinon.stub(TempTableDao, "getBookForUpdate").yields(jsonResult.single.failure.result);
  let getTempTableUpdateSpy = sinon.stub(TempTableDao, "updateBook");

  let test = nock('https://test.api.com/id')
    .get('/ID125125/')
    .reply(404, {

    });

  getTempTableUpdateSpy.callsFake(() => {
    sinon.assert.calledOnce(getTempTableForUpdateCountSpy);
    sinon.assert.calledOnce(getTempTableForUpdateSpy);
    test.interceptors[0].statusCode.should.be.equal(404);
    sinon.assert.calledOnce(getTempTableUpdateSpy);
    done();
  });

  updateTask.updateInfo();
});
Run Code Online (Sandbox Code Playgroud)