Javascript 在此模块外模拟Node.js模块中的构造函数(或其他函数)

Javascript 在此模块外模拟Node.js模块中的构造函数(或其他函数),javascript,unit-testing,node.js,tdd,mocking,Javascript,Unit Testing,Node.js,Tdd,Mocking,我使用Jasmine来编写测试,但我想任何其他测试框架都会有这个问题。假设我们有一个模块foo,有两个函数,Bar和Baz,它们是构造函数(但可能只是普通函数): 现在我想测试一下Bar,但是使用了一个假的Baz实现: var foo = require('foo'); describe("foo.Bar", function() { it("initializes its own Baz", function() { spyOn(foo, 'Baz'); // this repl

我使用Jasmine来编写测试,但我想任何其他测试框架都会有这个问题。假设我们有一个模块
foo
,有两个函数,
Bar
Baz
,它们是构造函数(但可能只是普通函数):

现在我想测试一下
Bar
,但是使用了一个假的
Baz
实现:

var foo = require('foo');

describe("foo.Bar", function() {
  it("initializes its own Baz", function() {
    spyOn(foo, 'Baz'); // this replaces foo.Baz with a fake implementation
    var bar = new foo.Bar();
    expect(foo.Baz).toHaveBeenCalled();
  });
});
问题是该测试将失败,因为
Bar
使用变量
Baz
实例化了一个新的
Baz
,该变量不能从外部更改。使用
spyOn()
交换的唯一东西是
exports.Baz


显而易见的解决方案是编写
this.baz=newexports.baz()但感觉有点尴尬。如果我想在模块中使用更多的函数,我必须始终使用
exports.
前缀调用所有函数。这里还有其他方法吗?

如果您能以某种方式将这两个类解耦,比如允许Baz类的其他实现提供给bar,那么我认为这是最好的方法,您应该这样做


但是,如果您真的希望能够将
exports.Baz
引用为
Baz
,那么我可以想到一种方法,将
一起使用

据说将
一起使用通常是一种不好的做法,应该避免,我不会在自己的代码中使用它,但这是解决问题的一种方法,甚至可以,只要您知道自己在做什么

下面是:

with(exports) {

    exports.Bar = function Bar() {
        console.log('this is bar!');
        this.baz = new Baz();
    };

    exports.Baz = function Baz() {
        console.log('original baz!');
    };

}
在另一个模块中,如果您将
foo.Baz
更改为其他内容,foo内部的
Baz
也将查找它


我仍然建议找到一种使这两个类相互独立的方法,然后您可以给Baz任何您想要的实现。

尝试
spyOn(window'Baz')
和'expect(window.Baz).toHaveBeenCalled();'@Prusse,我想Node没有
窗口
对象。对不起,如果有全局对象,您可以在适当的位置使用它。@Prusse,恐怕我不明白。什么是全局对象?难道没有一个关于没有全局对象的模块系统吗?将
一起使用很有意思,但我想这太不规范了。我不希望将这两个“类”解耦,因为
Baz
从未在
Bar
之外实例化过。您可以说,也许我不应该测试
Baz
,因为这是一个内部实现细节,但实际上整个系统的行为非常复杂,我需要更细粒度的测试。无论如何,谢谢你的提示。
with(exports) {

    exports.Bar = function Bar() {
        console.log('this is bar!');
        this.baz = new Baz();
    };

    exports.Baz = function Baz() {
        console.log('original baz!');
    };

}