nodejs - заглушка sinon не вызывается

По какой-то причине у меня возникли небольшие проблемы с корректным запуском этого простого теста с аналогичной настройкой, которую я использовал несколько раз раньше.

Возможно, свежий взгляд поможет мне понять, почему мой метод generateReport не вызывается, и ни один из моих stubs не запускается с предполагаемыми аргументами?

BYE и GOOD никогда не регистрируются, и тесты возвращают ошибку: AssertError: expected stub to be called with arguments

Мой индексный файл:

const errorHandler = require('./lib/handlers/error-handler')
const transformRequest = require('./lib/handlers/request-converter')
const convert = require('./lib/convert')

exports.generateReport = function generateReport(req, res) {
  console.log('HELLO')
  const objectToPopulateTemplate = transformRequest(req.body)
  convert(objectToPopulateTemplate, function (e, data) {
    if (e) {
      console.log('BYE')
      const error = errorHandler(e)
      return res.send(error.httpCode).json(error)
    }
    console.log('GOOD')
    res
      .set('Content-Type', 'application/pdf')
      .set('Content-Disposition', `attachment; filename=velocity_report_${new Date()}.pdf`)
      .set('Content-Length', data.length)
      .status(200)
      .end(data)
  })
}

Мой тестовый файл:

const proxyquire = require('proxyquire')
const assert = require('assert')
const sinon = require('sinon')
const fakeData = require('./data/sample-request.json')


describe('report-exporter', () => {
  describe('generateReport', () => {
    const fakeError = new Error('Undefined is not a function')

    let res, resSendStub, resStatusStub, resEndStub, resSetStub, resJsonStub, req, convertStub, generate
    before(() => {
      resSendStub = sinon.stub()
      resJsonStub = sinon.stub()
      resStatusStub = sinon.stub()
      resEndStub = sinon.stub()
      resSetStub = sinon.stub()
      convertStub = sinon.stub()

      res = {
        send: function(errorCode) {
          return resSendStub(errorCode)
        },
        json: function(object) {
          return resJsonStub(object)
        },
        set: function(arg1, arg2) {
          return resSetStub(arg1, arg2)
        },
        status: function(code) {
          return resStatusStub(code)
        },
        end: function(data) {
          return resEndStub(data)
        }
      }
      req = {
        body: {}
      }

      generate = proxyquire('./../index', {
        './lib/convert': function() {
          return convertStub
        }
      })
    })


    it('Should return an error response', () => {
      convertStub.throws(fakeError)
      generate.generateReport(req, res)
      sinon.assert.calledWith(resSendStub, '500')
    })
  })
})

person hyprstack    schedule 17.11.2017    source источник


Ответы (2)


Похоже, вы proxyquire пишете ./lib/convert неправильно. Исходный convert вызывается с objectToPopulateTemplate и обратным вызовом function (e, data). И это обратный вызов, который отвечает за обработку ошибок и отправку ответа.

Заглушенная функция convert, тем не менее, вообще не заботится о предоставленном обратном вызове, поэтому обратный вызов никогда не вызывается.

Скорее всего, вы хотите передать параметры в convertStub и обработать их позже:

'./lib/convert': function(objectToPopulateTemplate, cb) {
    return convertStub(objectToPopulateTemplate, cb);
}

а потом

it('Should return an error response', () => {
  generate.generateReport(req, res);
  const cb = convertStub.getCall(0).args[1];

  // simulate `convert` to fail
  cb(fakeError);

  sinon.assert.calledWith(resSendStub, '500')
})
person Sergey Lapin    schedule 17.11.2017

Вот решение модульного теста:

index.js:

const errorHandler = require("./error-handler");
const transformRequest = require("./request-converter");
const convert = require("./convert");

exports.generateReport = function generateReport(req, res) {
  console.log("HELLO");
  const objectToPopulateTemplate = transformRequest(req.body);
  convert(objectToPopulateTemplate, function(e, data) {
    if (e) {
      console.log("BYE");
      const error = errorHandler(e);
      return res.send(error.httpCode).json(error);
    }
    console.log("GOOD");
    res
      .set("Content-Type", "application/pdf")
      .set(
        "Content-Disposition",
        `attachment; filename=velocity_report_${new Date()}.pdf`
      )
      .set("Content-Length", data.length)
      .status(200)
      .end(data);
  });
};

error-handler.js:

module.exports = function(error) {
  return error;
};

request-converter.js:

module.exports = function transformRequest(body) {
  return body;
};

convert.js:

module.exports = function convert(body, callback) {
  callback();
};

index.spec.js:

const sinon = require("sinon");
const proxyquire = require("proxyquire");

describe("report-exporter", () => {
  describe("generateReport", () => {
    afterEach(() => {
      sinon.restore();
    });
    const fakeError = new Error("Undefined is not a function");
    fakeError.httpCode = 500;

    it("Should return an error response", () => {
      const logSpy = sinon.spy(console, "log");
      const mReq = { body: {} };
      const mRes = { send: sinon.stub().returnsThis(), json: sinon.stub() };
      const convertStub = sinon.stub();
      const errorHandlerStub = sinon.stub().returns(fakeError);
      const transformRequestStub = sinon.stub().returns(mReq.body);
      const generate = proxyquire("./", {
        "./convert": convertStub,
        "./error-handler": errorHandlerStub,
        "./request-converter": transformRequestStub
      });

      generate.generateReport(mReq, mRes);
      convertStub.yield(fakeError, null);
      sinon.assert.calledWith(transformRequestStub);
      sinon.assert.calledWith(convertStub, {}, sinon.match.func);
      sinon.assert.calledWith(errorHandlerStub, fakeError);
      sinon.assert.calledWith(logSpy.firstCall, "HELLO");
      sinon.assert.calledWith(logSpy.secondCall, "BYE");
    });
  });
});

Результат модульного теста с отчетом о покрытии:

  report-exporter
    generateReport
HELLO
BYE
      ✓ Should return an error response (94ms)


  1 passing (98ms)

----------------------|----------|----------|----------|----------|-------------------|
File                  |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s |
----------------------|----------|----------|----------|----------|-------------------|
All files             |     87.5 |       50 |     62.5 |     87.5 |                   |
 convert.js           |       50 |      100 |        0 |       50 |                 2 |
 error-handler.js     |       50 |      100 |        0 |       50 |                 2 |
 index.js             |    84.62 |       50 |      100 |    84.62 |             14,15 |
 index.spec.js        |      100 |      100 |      100 |      100 |                   |
 request-converter.js |       50 |      100 |        0 |       50 |                 2 |
----------------------|----------|----------|----------|----------|-------------------|

Исходный код: https://github.com/mrdulin/mocha-chai-sinon-codelab/tree/master/src/stackoverflow/47352972

person slideshowp2    schedule 21.11.2019