2015-12-24 2 views
1

Я пишу тесты для метода, который использует email-templates модуля вроде этого:Как заглушить nodejs "требуемый" конструктор, используя sinon?

var EmailTemplate = require('email-templates').EmailTemplate; 

module.exports = { 
    sendTemplateEmail: function (emailName, data, subject, to, from) { 
     var template = new EmailTemplate(__dirname + "/../emails/" + emailName); 

     data.from = FROM; 
     data.host = config.host; 

     return template.render(data) 
      .then(function (result) { 
       return mailer.sendEmail(subject, to, from, result.html, result.text); 
      }) 
      .then(function() { 
       log.info(util.format("Sent %s email to %s. data=%s", emailName, to, JSON.stringify(data))); 
       return Promise.resolve(); 
      }) 
      .catch(function (err) { 
       return Promise.reject(new InternalError(err, "Error sending %s email to %s. data=%s", emailName, to, JSON.stringify(data))); 
      }); 
    } 
}; 

Тест блока выглядит следующим образом:

var assert = require("assert"), 
    sinon = require("sinon"), 
    Promise = require("bluebird"), 
    proxyquire = require("proxyquire"); 

describe('mailer#sendTemplateEmail', function() { 
    var templates, 
     template; 

    beforeEach(function() { 
     templates = { 
      EmailTemplate: function(path) {} 
     }; 
     template = { 
      render: function(data) {} 
     }; 

     sinon.stub(templates, "EmailTemplate").returns(template); 
    }); 

    it("should reject immediately if template.render fails", function() { 
     const TO = {email: "[email protected]", first: "User"}; 
     const FROM = {email: "[email protected]", first: "User"}; 
     const EMAIL_NAME = "results"; 
     const SUBJECT = "Results are in!"; 
     const DATA = { 
      week: 10, 
      season: "2015" 
     }; 

     var err = new Error("error"); 
     var mailer = proxyquire("../src/mailer", { 
      "email-templates": templates 
     }); 

     sinon.stub(template, "render").returns(Promise.reject(err)); 

     return mailer.sendTemplateEmail(EMAIL_NAME, DATA, SUBJECT, TO, FROM) 
       .then(function() { 
        assert.fail("Expected a rejected promise."); 
       }) 
       .catch(function (err) { 
        assert(err.message === "error"); 
        assert(mailer.sendEmail.notCalled); 
       }); 
    }); 
}; 

Проблема Я сталкиваюсь находится на первом строка функции sendTemplateEmail, которая создает новый объект EmailTemplate. Вызываемый конструктор EmailTemplate указывает на функцию non-stub EmailTemplate, определенную в beforeEach, а не на синус-заглушку, созданную на последней строке beforeEach. Однако, если я оцениваю оператор require('email-templates').EmailTemplate, он правильно указывает на синус-заглушку. Я предпочел бы не иметь, чтобы изменить свой код для вызова требуется заявление инлайн как:

var template = new require('email-templates').EmailTemplate(__dirname + "/../emails/" + emailName); 

Есть ли способ сделать окурок путем я намеревающийся?

ответ

1

Вы можете вводить вашу зависимость, когда вы строите свой почтовик - ехр:

function mailer(options) { 
    options = options || {}; 
    this.email_template = options.email_template; 
} 

Тогда в функции sendTemplateEmail - использовать email_template элемент.

Кроме того - не уверен, что ваш код почтовой программы - но если вам нужна ваша почтовая программа, чтобы выступать в качестве одноэлементных в коде (и это не уже) - вы можете добавить к вашей почтовой программе:

module.exports = { 
    getInstance: function(emailTemplate) { 
     if(this.instance === null){ 
      this.instance = new mailer(emailTemplate); 
     } 
     return this.instance; 
    } 
} 

Затем, когда вы требуете вашего почтовика вы можете использовать синтаксис:

var template = new require('email-templates').EmailTemplate(__dirname + "/../emails/" + emailName); 
var mail = mailer.getInstance(template); 

Таким образом, приложение (модульное тестирование рамка или ваш фактическое применение/в реальном мире) будет определять тип почтовой программы, которая будет использоваться для жизни процесса.

+0

Я надеялся, что есть какой-то способ избежать inline require, но это, по крайней мере, будет содержать мой код приложения в чистоте. – Jared

Смежные вопросы