【问题标题】:How to stub an object method with sinon?如何用 sinon 存根对象方法?
【发布时间】:2019-09-12 01:57:40
【问题描述】:

我需要存根 mh 对象的 sendMandrill 方法。

查看我的测试文件(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: {...}
        });
    }
    ...
}

【问题讨论】:

  • 你能发一个邮件处理模块的sn-p吗?
  • @WakeskaterX 为什么这有关系?将 MailHandler 视为必须实例化的泛型类,并且必须存根的方法位于生成的对象中。
  • 尝试将:sinon.stub(MailHandler.prototype, 'sendMandrill', () => true); 更改为:sinon.stub(MailHandler, 'sendMandrill', () => true); 阅读更多:medium.com/@alfasin/stubbing-with-sinon-4d6539caf365
  • 谢谢@alfasin - 不幸的是我得到了同样的错误。
  • 也就是说MailHandler没有这个功能。你确定你导入正确吗?尝试用调试器踩一下,看看MailHandler 长什么样子

标签: node.js sinon


【解决方案1】:

您当前的方法为mailHandler 工厂创建的每个实例创建一个新的sendMandrill。您实际上应该将其命名为不带新的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() {} })

【讨论】:

  • 谢谢@Yury Tarabanko。我无法控制 mail.handler.module 所以我不能在那里改变任何东西。我需要做的是模拟我必须测试的函数(“发送”)所具有的依赖项。 "send" 获取对 MailHandler() 返回的对象的引用(如果使用 "new" 调用新实例,或者引用现有对象,则无关紧要)。我必须存根该对象的方法“sendMandrill”。你是说通过 sinon 存根依赖的唯一方法是存根原型?
  • @Miki 如果您不拥有mailHandler,那么我建议使用rewire 来模拟整个依赖项。或者通过api.ModuleHandler = require('../../modules/mail.handler.module') 和使用let mh = api.ModuleHandler() 使其“可注入”。那么你就可以在你的测试中注入任何实现。
  • 好吧,我按照你的建议让 MailHandler 可注入,现在我可以存根了。
猜你喜欢
  • 1970-01-01
  • 2014-07-17
  • 2018-05-31
  • 1970-01-01
  • 2015-04-18
  • 2018-07-16
  • 1970-01-01
  • 2016-01-02
  • 2021-06-10
相关资源
最近更新 更多