如何使用sinon来模拟作为函数导出的节点模块的函数/属性?

我有一个作为function导出的服务模块。 我需要传递一些东西,像一个configuration对象,所以它需要保留这个结构。 我正在尝试从服务中删除一个函数,但无法弄清楚。 在我的应用程序,我有一个函数,使testing期间有问题的API调用,所以我想存根。 (我知道我必须写我的testing不同来处理asynchronous问题)

// myService.js module.exports = function(config) { function foo() { returns 'bar'; } return { foo: foo }; }; // test.js var config = require('../../config'); var request = require('supertest'); var chai = require('chai'); var expect = chai.expect; var sinon = require('sinon'); var myService = require('./myService.js')(config); describe('Simple test', function(done) { it('should expect "something else", function(done) { var stub = sinon.stub(myService, 'foo').returns('something else'); request(server) // this object is passed into my test. I'm using Express .get('/testRoute') .expect(200) .expect(function(res) { expect(res.body).to.equal('something else'); stub.restore(); }) .end(done); }); }); * /testRoute I set up as a simple GET route that simply returns the value from myService.foo() 

以上不起作用,我相信这与我的服务出口的方式有关。 如果我写如下服务,存根工作正常。

 module.exports = { test: function() { return 'something'; } }; 

但是,我又需要能够将信息传递给模块,所以我想将模块保留在上面的原始结构中。 有没有一种方法来存储以这种方式导出的模块中的函数? 我也正在寻找代理,但不知道这是否是答案。

testing存根不起作用的原因是foo函数每次调用模块初始化函数时都会创build。 正如你发现的那样,当你在模块上有一个静态方法时,你就可以存根。

这个问题有多种解决scheme,但最简单的方法是静态地公开方法。

 // myService.js module.exports = function(config) { return { foo: foo }; }; var foo = module.exports.foo = function foo() { return 'bar' } 

这是丑陋的,但工程。

如果foo函数对服务中的variables有一个闭包(这就是它存在于服务初始化程序中的原因)。 那么不幸的是,这些需要明确的传入。

 // myService.js module.exports = function(config) { return { foo: foo }; }; var foo = module.exports.foo = function(config) { return function foo() { return config.bar; } } 

现在,您可以安全地存根模块。

但是,如何剔除应该被认为是不安全的。 只有当你的testing完美的工作,存根被清理。 您应该始终在before (或beforeafter )夹具存根,如:

 // We are not configuring the module, so the call with config is not needed var myService = require('./myService.js'); describe('Simple test', function(done) { beforeEach(function () { // First example, above this.myStub = sinon.stub(myService, foo).returns('something else'); // Second example, above this.myStub = sinon.stub(myService, foo).returns(function () { returns 'something else'; }); }); afterEach(function () { this.myStub.restore(); }); it('should expect "something else", function(done) { request(server) // this object is passed into my test. I'm using Express .get('/testRoute') .expect(200) .expect(function(res) { expect(res.body).to.equal('something else'); }) .end(done); }); }); 

还有其他选项可以使用dependency injection来存根相关性。 我build议你看看https://github.com/vkarpov15/wagner-core或我自己的https://github.com/CaptEmulation/service-builder