Node.js 我可以在外部模块函数中使用sinon监视函数调用吗?

Node.js 我可以在外部模块函数中使用sinon监视函数调用吗?,node.js,sinon,Node.js,Sinon,我有一个模块: let xmlParser = require('./myTools').xmlParser; function extractDataAndWrite(xmldata) { let doc = xmlParser(xmldata); ... } module.exports = { extractDataAndWrite, }; 现在我想在extractDataAndWrite中测试xmlParser的调用: var extractDataAndW

我有一个模块:

let xmlParser = require('./myTools').xmlParser;

function extractDataAndWrite(xmldata) {
    let doc = xmlParser(xmldata);
    ...
}

module.exports = {
    extractDataAndWrite,
};
现在我想在
extractDataAndWrite
中测试
xmlParser
的调用:

var extractDataAndWrite = require('../services/importData.js').extractDataAndWrite;
var mytools = require('./myTools');

var sinon = require('sinon');

describe('Test extractDataAndWrite', function() {
    it('call xmlParser', function(done) {
        var xmlParserSpy = sinon.spy(mytools, 'xmlParser');

        extractDataAndWrite("someXML");

        console.log('xmlParserSpy: ' + xmlParserSpy.callCount);
        done();
    });
});
我希望get
xmlParserSpy.callCount==1
,但它是0!
My spy不工作,我必须更改什么?

问题是,当您在函数上创建
spy
时,您正在用新函数替换该函数引用。这意味着引用旧函数的用户将不会使用新函数。在您的情况下,当您自己的模块已经引用了旧的函数引用之后,在
mytools
”中包装导出的函数引用时,一切都不起作用

您需要研究的一般技术称为依赖项注入和链接接缝。Sinon文档有一个,使用
proxyquire

基本上你会有这样的想法:

const proxyquire = require('proxyquire');
const toolsStub = createToolsStub();
const importData = proxyquire('../services/importData.js', {
    './myTools': toolsStub
});

function createToolsStub(){
    return { xmlParser : sinon.stub().returns({mydoc:{foo:'bar'}};
}
然后在稍后的测试中,您可以检查
xmlParser
中的调用

assert(toolsStub.xmlParser.calledWith('arg1', 'arg2');

添加了一个解释为什么它不起作用的答案,以及一种可以解决问题的技术非常有用。但是它不能与自己的模块一起工作;does-file-exist.js:var mtools=require(“../lib/mytools”);函数doesFileExist(path){return mtools.xmlParser(path);//return fs.existsSync(path);}does-file-exist.test.js doesFileExist=proxyquire(“../lib/does-file-exist”,{mtools:{xmlParse:existsSyncStub});测试失败!!!为什么?当你寻求帮助时,说出失败的地方会有帮助:-)并且
proxyquire
可以很好地与本地模块配合使用。。。但不管怎样,我提取了你的代码,格式化了它,然后。很容易看出这不起作用的原因:您没有指定模块的正确路径。我将用正确的代码更新我的jsbin。如果它解决了你的问题,考虑将答案标记为“解决”。