Как заглушить объектный метод с помощью sinon? - PullRequest
0 голосов
/ 23 апреля 2019

Мне нужно заблокировать метод sendMandrill объекта mh.

См. Мой тестируемый файл (mail.js):

let MailHandler = require('../../modules/mail.handler.module');
...
let api = (router, parser) => {
   let send = async (req, res, next) => {
      let mh = new MailHandler();
      mh.sendMandrill();    
      ...
   }
   ...    
   return router.post('/mail/send', parser.json(), send);
}
module.exports = api;
...

Мой тест (mail.spec.js):

let stRequest = require('supertest');
let MailHandler = require('../../modules/mail.handler.module');
describe('my test', () => {
   beforeEach(() => {
      sinon.stub(MailHandler.prototype, 'sendMandrill', () => true);
   })
   it('stubs sendMandrill!', done => {
      stRequest(app)
         .post('/mail/send')
            .end((err, resp) => {
                done();
            });
   })
})

В настоящее время я получаюошибка ниже:

TypeError: Cannot stub non-existent own property sendMandrill

Добавление mail.handler.module - см. ниже код mailHandler / sendMandrill:

module.exports = mailHandler;

function mailHandler() {
    ...
    var mandrill = require('../modules/mandrill');

    var handler = {
        sendMandrill: sendMandrill,
        ...
    };

    return handler;

    function sendMandrill() {
        mandrill.messages.sendTemplate({
            message: {...}
        });
    }
    ...
}

1 Ответ

1 голос
/ 23 апреля 2019

Ваш текущий подход создает новый sendMandrill для каждого экземпляра, созданного фабрикой mailHandler.Вы должны назвать его без let mh = mailHandler() или даже лучше переименовать в createMailHandler, чтобы избежать неправильного использования.

Если вы хотите эффективно использовать наследование прототипа, вам нужно переписать mailHandler, чтобы использовать фактически this вместо вновь созданного объекта.

var mandrill = require('../modules/mandrill');

module.exports = MailHandler;

function MailHandler() {
    // use this instead of newly created object
    this.foo = 'bar'

    // avoid explicit return
    // return handler;
}

// set methods to prototype
MailHandler.prototype.sendMandrill = function sendMandrill() {
        // use this instead of handler here
        mandrill.messages.sendTemplate({
            message: {...}
        });
    }

Использование вышеупомянутого подходавы сможете заглушить свойства прототипа через sinon и оправдать вызов конструктора с ключевым словом new.

UPD

Если у вас нет контроля над mail.handler.module, вы можете использовать модуль rewire, который позволяет имитировать все зависимости, или выставлять MailHandler как часть.вашего api модуля, чтобы сделать его инъекционным.

api.MailHandler = require('../../modules/mail.handler.module')

let mh = api.MailHandler();

А затем в тестах

let oldMailHandler;

beforeAll(() => { oldMailHandler = api.MailHandler})
afterAll(() => { api.MailHandler = oldMailHandler})
beforeEach(() => { api.MailHandler = function MockMailHandler() {} })
...