Sinon.stub 不存根私有方法

Sinon.stub not stubbing private method

在下面的模块中,我有一个创建临时目录的私有方法。我正在为这个模块 resize 编写测试,并希望将其私有方法 createTmpFile 和 return 存入一个假目录。我正在使用 sinon 来执行此操作,但仍在调用原始方法。

我试过用 var _private = require('../lib/modules/resizer')._private; 要求私有方法,然后用 tmpStub = sinon.stub(_private, 'createTmpFile', function () { return "/temporary/"});

在我的测试服中存根它

这不会引发任何错误,但仍会停止调用该函数。

如何用存根替换私有方法?

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,其中包含对您的私有函数的 引用。您正在用存根替换引用,但这与对原始函数进行存根不同。

除非您在调整大小函数中实际使用 exports._private.createTmpFile(这不是您想要的,因为 exports._private 仅存在于 test 环境中),否则您不会使用stub 而是实际函数(因为 createTmpFile 仍然指向原始函数)。

老实说,不确定是否有解决这个问题的干净方法。

感谢@robertklep 的评论,我决定再次用 proxyquire 解决这个问题,并得出以下通过我测试的解决方案。

我更改了设置,将 tmp.dirSync 添加到 proxyquire 并将其强制到 return 假目录。我还删除了临时目录的存根。

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/');
    });
});