【问题标题】:sinon stub not replacing function.sinon 存根没有替换功能。
【发布时间】:2018-08-02 13:31:04
【问题描述】:

我尝试了一个虚拟模块并将其存根,但不起作用。

app.js

function foo()
{
    return run_func()
}
function run_func()
{
    return '1'
}
exports._test = {foo: foo, run_func: run_func}

test.js

app = require("./app.js")._test
describe('test', function(){
    it('test', function(){

        var test_stub = sinon.stub(app, 'run_func').callsFake(
          function(){
            return '0'
        })
        test_stub.restore()

        var res = app.foo()
        assert.equal('0', res)
    })
})

我尝试了以下建议: sinon stub not replacing function

但还是一样。它不会取代函数。

【问题讨论】:

    标签: javascript node.js testing mocha.js sinon


    【解决方案1】:

    这里有几个问题。第一个是您在创建存根后立即调用test_stub.restore(),这会导致它用原始函数替换自己,从而有效地完全撤消存根。

    restore 用于在测试完成后清理虚假方法。所以你确实想调用它,但你应该在 afterEach. 中这样做

    您的第二个问题更微妙。 Sinon 的工作原理是覆盖对象上对函数的引用,使其指向其他对象(在本例中为存根)。它不能替换其他上下文中对同一函数的引用。

    当你拨打sinon.stub(app, 'run_func')时,有点像这样:

    app.run_func = sinon.stub()
    

    ...除了前一种方式存储app.run_func的原始值和名称,方便您以后轻松恢复。

    请注意,此时变量app 指向您使用exports._test = {foo: foo, run_func: run_func} 导出的同一对象,但是您的foo 函数并未通过该对象引用run_func。是直接在app.js的范围内引用,sinon不能影响。

    看看下面的例子。你还会注意到我清理了其他一些东西:

    app.js:

    exports.foo = function() {
        return exports.run_func();
    };
    
    exports.run_func = function() {
        return '1';
    };
    

    test.js:

    const app = require('./app');
    const sinon = require('sinon');
    
    describe('app', function() {
        describe('foo', function() {
            beforeEach(function() {
                sinon.stub(app, 'run_func').returns('0');
            });
    
            afterEach(function() {
                app.run_func.restore();
            });
    
            it('returns result of app.run_func', function() {
                assert.equal(app.foo(), '0');
            });
        });
    });
    

    请注意app.js 中的exportsapptest.js 中所指的对象完全相同。这是因为 node 中的模块默认导出一个空对象,您可以通过 exports 变量对其进行赋值。

    【讨论】:

    • 谢谢!我是 JavaScript 的新手,所以似乎 export._test = {foo: foo, run_func: run_func} 创建了一个包含原始函数对象副本的新对象(我不知道这样说是否正确,我来自 c++),我认为它引用了原始对象。我必须直接导出函数对象而不是副本?
    • 从 C/C++ 的角度来看,将 javascript 中的每个变量或对象属性视为一个指针会有所帮助。您并没有将函数复制到新对象,而是给它引用,以便您可以通过它访问函数。 exports 是你require 模块时默认返回的对象。默认情况下它是一个空对象,您可以将函数引用分配给它以“导出”它们。这是一个相当不错的教程:sitepoint.com/understanding-module-exports-exports-node-js
    • 有没有办法替换函数,不管它是怎么调用的?
    • @Ashokkumar 不幸的是,没有。此限制内置于 JavaScript 的工作方式中。在 CommonJS 模块中,该模块顶层的变量是模块本地的,不能从模块外部更改。因此,您需要通过可在模块外部访问的对象来引用可替换的东西。大多数时候,默认导出对象是最好的候选对象。
    猜你喜欢
    • 2017-04-09
    • 1970-01-01
    • 2018-11-22
    • 1970-01-01
    • 2019-04-03
    • 2018-05-27
    • 2019-07-22
    • 2016-09-30
    • 1970-01-01
    相关资源
    最近更新 更多