【问题标题】:Jasmine - Spying on a method call within a constructorJasmine - 在构造函数中监视方法调用
【发布时间】:2012-01-04 21:02:37
【问题描述】:

我想测试是否在我的 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();
});

【问题讨论】:

    标签: javascript testing jasmine spy


    【解决方案1】:

    直接窥探原型方法:

    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();
      });
    });
    

    【讨论】:

    • 谢谢你。我整天看到的关于这个主题的最佳描述
    • 预感有一个合法的解决方案。谢谢。
    • 这种方法有两个问题。首先,它会导致内存泄漏——所有未来的 Klass 实例都将被调用的方法被调用,并且随着更多调用的进行,spy 的内存消耗将会增加。其次,更令人担忧的是,这也可能导致审问 Klass 的多个测试相互交互,因为已经调用了间谍。您应该确保在测试用例结束时删除了 spy 或将 Klass.prototype.called_method 重置为原始方法。
    • @alecmce 请回答这个问题。我问 Jasmine 的人这是一种有效的方法,并被告知这是一个警告,如果不是,似乎用更安全的解决方案来回答它是合适的,不是吗?
    • Jasmine 1.3.1+ 在规范完成后完全恢复功能,因此副作用不再是问题,不再需要重置方法。耶!供参考:github.com/jasmine/jasmine/issues/236
    【解决方案2】:

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

    使用另一个测试用例对 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 方法。

    【讨论】:

    • +1,感谢您提供更多信息。我认为底部的“注意”部分几乎总结了所有内容。几乎可以肯定它应该在其他地方而不是在测试中修复。
    • 是的,我想他们不久前就关闭了这个问题。原则上仍然值得避免监视原型。
    猜你喜欢
    • 2012-03-09
    • 1970-01-01
    • 2012-01-09
    • 2018-12-30
    • 1970-01-01
    • 2018-03-31
    • 1970-01-01
    • 2017-10-22
    • 2014-01-25
    相关资源
    最近更新 更多