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

时间:2011-11-11 16:41:27

标签: javascript unit-testing node.js tdd mocking

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

var Bar = exports.Bar = function Bar() {
  this.baz = new Baz();
};

var Baz = exports.Baz = function 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 = new exports.Baz();,但有点尴尬。如果我想在模块中使用更多函数,我必须始终使用exports.前缀调用所有函数。这里还有其他方法吗?

1 个答案:

答案 0 :(得分:1)

如果你能以某种方式解耦这两个类,比如允许Baz类的其他实现被赋予bar,那么我认为这是最好的方法,你应该去实现它。


但如果您真的希望能够将exports.Baz称为Baz,那么我可以使用with找到一种方法。

据说使用with通常是一种不好的做法,应该避免使用,我不会在我自己的代码中使用它,但这是解决它的一种方法,甚至可以{{3}只要你知道你在做什么。

这就是:

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也会查找它。

我仍然建议找到一种方法让这两个类彼此独立,然后你可以给Bar吧你想要的任何Baz实现。