Sinon.stub不会吝啬私人方法

在下面的模块中,我有一个私人的方法,创build一个临时目录。 我正在编写这个模块的testing, resize ,并希望存根其私有的方法createTmpFile并返回一个虚假的目录。 我正在用sinon做这个,但是原来的方法仍然被调用。

我已经尝试要求var _private = require('../lib/modules/resizer')._private; 然后用tmpStub = sinon.stub(_private, 'createTmpFile', function () { return "/temporary/"});tmpStub = sinon.stub(_private, 'createTmpFile', function () { return "/temporary/"});我的testing套装中tmpStub = sinon.stub(_private, 'createTmpFile', function () { return "/temporary/"});

这不会抛出错误,但仍然停止被调用的function。

我如何用存根replace私有方法?

resize

 'use strict'; // dependencies var gm = require('gm').subClass({ imageMagick: true }); var tmp = require('tmp'); var async = require('async'); var resizer = {}; resizer.resize = function (path, sizesObj, callback) { console.log(path); var directory = createTmpFile(); var imgType = path.split(".").pop(); async.each(sizesObj, function (sizesObj, mapNext) { gm(path) .resize(sizesObj.width, sizesObj.height) .write(directory + sizesObj.name + "." + imgType, function (err) { if (err) { mapNext(err); } mapNext(); }); }, function (err) { if(err) { callback(err); } else { callback(directory); } }); }; // This function creates a temporary directory to which we will save our files. var createTmpFile = function () { var tmpDir = tmp.dirSync(); //object var tmpDirName = tmpDir.name + "/"; //path to directory return tmpDirName; }; module.exports = resizer; if ( process.env.NODE_ENV === 'test') { module.exports._private = { createTmpFile: createTmpFile } }; 

test

  describe("resizer when data is path", function () { var testedModule, dir, sizesObj, tmpStub, writeStub250, writeStub500, writeStub650, writeStub750, callbackSpy, resizeStub, gmSubClassStub; var _private = require('../lib/modules/resizer')._private; console.log(_private.createTmpFile); before(function () { dir = "/tmp/rstest.png"; sizesObj = [ {name: "thumb", width: 250, height: 250}, {name: "small", width: 500, height: 500}, {name: "medium", width: 650, height: 650}, {name: "large", width: 750, height: 750} ]; writeStub250 = sinon.stub(); writeStub500 = sinon.stub(); writeStub650 = sinon.stub(); writeStub750 = sinon.stub(); resizeStub = sinon.stub(); tmpStub = sinon.stub(_private, 'createTmpFile', function () { return "/temporary/"}); gmSubClassStub = sinon.stub(); callbackSpy = sinon.spy(); testedModule = proxyquire('../lib/modules/resizer', { 'gm': {subClass: sinon.stub().returns(gmSubClassStub)} }); }); after(function () { _private.createTmpFile.restore(); }); it("resize image and write to path", function () { resizeStub.withArgs(250, 250).returns({write:writeStub250}); resizeStub.withArgs(500, 500).returns({write:writeStub500}); resizeStub.withArgs(650, 650).returns({write:writeStub650}); resizeStub.withArgs(750, 750).returns({write:writeStub750}); // Stub is used when you just want to simulate a returned value gmSubClassStub.withArgs(dir).returns({resize:resizeStub}); // Act - this calls the tested method testedModule.resize(dir, sizesObj, function (err) { callbackSpy.apply(null, arguments); }); expect(writeStub250).has.been.called.and.calledWith("/temporary/thumb.png"); }); }); 

问题是,你正在保存_private.createTmpFile ,其中包含您的私人函数的引用 。 你用存根来代替引用,但是这不同于原始函数的存根。

除非在resize函数中实际使用exports._private.createTmpFile (这不是你想要的,因为exports._private只存在于test环境中),否则将不会使用存根,而是实际的函数(因为createTmpFile仍指向原来的function)。

不知道是否有一个干净的方法来解决这个问题,说实话。

所以感谢@robertklep评论,我决定再次用proxyquire解决这个问题,并通过了我的testing。

我已经通过将tmp.dirSync添加到proxyquire来更改设置,并强制它返回假目录。 我也删除了临时目录的存根。

 describe("resizer when data is path", function () { var testedModule, dir, sizesObj, writeStub250, writeStub500, writeStub650, writeStub750, callbackSpy, resizeStub, gmSubClassStub; before(function () { dir = "/tmp/rstest.png"; sizesObj = [ {name: "thumb", width: 250, height: 250}, {name: "small", width: 500, height: 500}, {name: "medium", width: 650, height: 650}, {name: "large", width: 750, height: 750} ]; writeStub250 = sinon.stub(); writeStub500 = sinon.stub(); writeStub650 = sinon.stub(); writeStub750 = sinon.stub(); resizeStub = sinon.stub(); gmSubClassStub = sinon.stub(); callbackSpy = sinon.spy(); testedModule = proxyquire('../lib/modules/resizer', { 'gm': {subClass: sinon.stub().returns(gmSubClassStub)}, 'tmp': { 'dirSync': function () { return { name: "/temporary" } } } }); }); it("resize image and write to path", function () { resizeStub.withArgs(250, 250).returns({write:writeStub250}); resizeStub.withArgs(500, 500).returns({write:writeStub500}); resizeStub.withArgs(650, 650).returns({write:writeStub650}); resizeStub.withArgs(750, 750).returns({write:writeStub750}); // Stub is used when you just want to simulate a returned value gmSubClassStub.withArgs(dir).returns({resize:resizeStub}); // Act - this calls the tested method testedModule.resize(dir, sizesObj, function (err) { callbackSpy.apply(null, arguments); }); expect(writeStub250).has.been.called.and.calledWith("/temporary/thumb.png"); expect(writeStub500).has.been.called.and.calledWith("/temporary/small.png"); expect(writeStub650).has.been.called.and.calledWith("/temporary/medium.png"); expect(writeStub750).has.been.called.and.calledWith("/temporary/large.png"); }); it("calls callbackSpy", function () { writeStub250.callsArgWith(1, null); writeStub500.callsArgWith(1, null); writeStub650.callsArgWith(1, null); writeStub750.callsArgWith(1, null); resizeStub.withArgs(250, 250).returns({write:writeStub250}); resizeStub.withArgs(500, 500).returns({write:writeStub500}); resizeStub.withArgs(650, 650).returns({write:writeStub650}); resizeStub.withArgs(750, 750).returns({write:writeStub750}); // Stub is used when you just want to simulate a returned value gmSubClassStub.withArgs(dir).returns({resize:resizeStub}); // Act - this calls the tested method testedModule.resize(dir, sizesObj, function (err) { callbackSpy.apply(null, arguments); }); expect(callbackSpy).has.been.called.and.calledWith('/temporary/'); }); });