64

我想测试在我的 Javascript 对象构造函数中是否调用了以下方法。从我在 Jasmine 文档中看到的内容来看,我可以监视构造函数方法,并且可以在实例化对象后监视方法,但我似乎无法在构造对象之前监视方法。

物体:

Klass = function() {
    this.called_method();
};

Klass.prototype.called_method = function() {
  //method to be called in the constructor.
}

我想在规范中做这样的事情:

it('should spy on a method call within the constructor', function() {
    spyOn(window, 'Klass');
    var obj = new Klass();
    expect(window.Klass.called_method).toHaveBeenCalled();
});
4

2 回答 2

113

直接窥探原型方法:

describe("The Klass constructor", function() {
  it("should call its prototype's called_method", function() {
      spyOn(Klass.prototype, 'called_method');  //.andCallThrough();
      var k = new Klass();
      expect(Klass.prototype.called_method).toHaveBeenCalled();
  });
});
于 2012-01-04T21:53:39.980 回答
12

总的来说,我同意戴夫牛顿上面的回答。但是,您应该考虑这种方法的一些边缘情况。

使用另一个测试用例对 Dave 的解决方案进行变体:

// production code
var Klass = function() {
  this.call_count = 0;
  this.called_method();
};
Klass.prototype.called_method = function() {
  ++this.call_count;
};

// test code
describe("The Klass constructor", function() {
  it("should call its prototype's called_method", function() {
    spyOn(Klass.prototype, 'called_method');
    var k = new Klass();
    expect(k.called_method).toHaveBeenCalled();
  });
  it('some other test', function() {
    var k = new Klass();
    expect(k.call_count).toEqual(1);
  });
});

第二个测试将失败,因为第一个测试中的间谍设置​​持续跨越测试边界进入第二个方法;called_method 不会增加 call_count,因此 this.call_count 不等于 1。也可能会提出带有误报的场景 - 测试通过,但不应该。

最重要的是,由于 spy 仍然存在,创建的 Klass 实例越多,spy 将消耗的内存堆越大,因为 spy 会记录对 called_method 的每次调用。在大多数情况下,这可能不是问题,但您应该意识到这一点,以防万一。

解决此问题的一个简单方法是确保在使用间谍后将其删除。它可能看起来有点难看,但这样的工作:

// test code
describe("The Klass constructor", function() {
  it("should call its prototype's called_method", function() {
    var spy = jasmine.createSpy('called_method');
    var method = Klass.prototype.called_method;
    Klass.prototype.called_method = spy;
    var k = new Klass();
    expect(spy).toHaveBeenCalled();
    Klass.prototype.called_method = method;
  });

[注意-完成一点意见]更好的解决方案是改变编写生产代码的方式,使代码更容易测试。通常,对原型进行间谍活动可能是一种需要避免的代码气味。与其在构造函​​数中实例化依赖项,不如注入它们。不要在构造函数中进行初始化,而是使用适当的 init 方法。

于 2013-11-19T05:51:27.313 回答