【问题标题】:Mocking a constructor (or other function) in a Node.js module outside of this module在该模块之外的 Node.js 模块中模拟构造函数(或其他函数)
【发布时间】:2011-12-27 04:23:27
【问题描述】:

我正在使用 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. 前缀来调用它们。这里还有其他方法吗?

【问题讨论】:

  • 试试spyOn(window, 'Baz'); 和`expect(window.Baz).toHaveBeenCalled();'。
  • @Prusse,我猜 Node 没有 window 对象。
  • 抱歉,如果有全局对象,您可以就地使用它。
  • @Prusse,恐怕我不明白。什么全局对象?没有一个没有全局对象的模块系统吗?

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


【解决方案1】:

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


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

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

这里是:

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 实现。

【讨论】:

  • 使用with 很有趣,但我想这太老套了。我不希望将这两个“类”解耦,因为Baz 永远不会在Bar 之外实例化。你可以说也许我不应该测试Baz,因为它是一个内部实现细节,但实际上整个系统的行为非常复杂,我需要更细粒度的测试。无论如何感谢您的提示。
猜你喜欢
  • 2014-01-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-28
  • 1970-01-01
  • 2019-11-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多