存根和代理

Stubs and proxquire

我在使用 proxyquire 后使用 sinon 存根特定函数时遇到问题。

示例:

// a.js
const api = require('api');

module.exports = (function () {
    return {
        run,
        doStuff
    };

    function run() {
        return api()
            .then((data) => {
                return doStuff(data);
            })
    }

    function doStuff(data) {
        return `Got data: ${data}`;
    }
})()

// a.spec.js - in the test
a = proxyquire('./a', {
    'api': () => Promise.resolve('data')
})
sinon.stub(a, 'doStuff');
// RUN TEST - call a.run()

我知道它不起作用,因为它调用原始的 doStuff 而不是 mocked/stubbed doStuff。

I know it isn't working because it calls the original doStuff instead of a mocked/stubbed doStuff.

这是因为 a.js 中的 function run() 在闭包内调用 function doStuff(data) function run() 保留了 a.js 而不是 a_spec.js.

中的 function doStuff(data)

举例说明

让我们将 a.js 重写为:

var a = 'I am exported';
var b = 'I am not exported';

function foo () {
    console.log(a);
    console.log(this.b)
}

module.exports.a=a;
module.exports.foo=foo;

和a.spec.js到:

var one = require('./one');

console.log(one); // { a: 'I am exported', foo: [Function: foo] }

one.a = 'Charles';
one.b = 'Diana';

console.log(one); // { a: 'Charles', foo: [Function: foo], b: 'Diana' }

现在如果我们调用 one.foo() 它将导致:

I am exported
Diana

I am exported 被记录到控制台,因为 foo 内的 console.log(a) 指向闭包内的 var a foo 保留了 a.js.

Diana 被记录到控制台,因为 foo 中的 console.log(this.b) 指向 a.spec.js[=55= 中的 one.b ].

那么你需要做什么才能让它发挥作用?

您需要更改:

module.exports = (function () {
    return {
        run,
        doStuff
    };

    function run() {
        return api()
            .then((data) => {
                return doStuff(data);
            })
    }

    function doStuff(data) {
        return `Got data: ${data}`;
    }
})()

至:

module.exports = (function () {
    return {
        run,
        doStuff
    };

    function run() {
        return api()
            .then((data) => {
                return this.doStuff(data); // ´this.doStuff´ points to ´doStuff´ in the exported object
            }.bind(this)) // to ensure that ´this´ does not point to the global object
    }

    function doStuff(data) {
        return `Got data: ${data}`;
    }
})()