JS:在对象实例化之前替换函数定义

时间:2014-07-22 16:40:00

标签: javascript backbone.js requirejs jasmine

我的require.js模块中有 outerViewinnerView。它们可以用很少的陈述来描述:

  • InnerView已在OuterView呈现
  • 上实例化
  • InnerView在自己的实例化上调用calculated方法
  • InnerView.calculate方法使用AJAX,这在单元测试中是不受欢迎的(使用jasmine)

我需要:在我的jasmine测试中使用硬编码innerView.calculate参数直接调用innerView.handleResults来替换data方法调用。

问题:问题还在于测试中我只能访问outerView。所以我需要在innerView.calculate实例化之前替换innerView方法定义。

问题: 如何在innerView.calculated实例化之前替换innerView方法定义?

代码:

    define(".....", function(...) {
      var innerView = Backbone.View.extend ({
        initialize: function() {
          ......
          calculate(opitons);
        },

        //I NEED TO REPLACE THIS WITH handleResults(hardcodedData)
        calculate: function(options) { 
          var $this = this;
          Utils.doSmth(options).then(
              $this.handleResults
          );
        },

        handleResults: function(data) {
          ....
        }
      });

      var outerView = Backbone.View.extend ({
        subViews: [],

        render: function() {
          subViews[0] = new innerView();
        }    
      });

      return outerView;
}

2 个答案:

答案 0 :(得分:1)

请记住,BDD的理念是测试行为。问问自己,你真的想改变你的功能在单元测试中的工作方式吗?通过提供备用代码路径,您不会测试您将在生产中看到的实际行为。

例如,如果在您的then函数中执行更复杂的数据按摩而不是简单地调用handleResults(...),该怎么办?然后,您需要将此逻辑的知识带入单元测试中,这样您就可以正确地模拟链的其余部分。

听起来我真正需要的是一种模拟AJAX请求的方式,而不是改变代码工作方式的方法。有几种方法可以实现这一目标。其中两个最受欢迎的是:

  • jasmine-ajax - 特定于茉莉花
  • Sinon.JS - 用于创建间谍,模拟和模拟HTTP服务器的独立框架。

我已经将Sinon.JS用于测试与XHR相关的代码路径,效果非常好。

答案 1 :(得分:1)

这看起来像是一个设计问题。你对outerView中的innerView类型有一个硬编码的依赖,你将它隐藏在一个闭包(aka模块)中。更糟糕的是,内部的,硬编码的依赖关系被连接到宇宙的其余部分(AJAX调用)。你必须以某种方式公开内部视图,以使其可测试。

在我看来,至少,你必须像这样打开你的外部视图:

var outerView = Backbone.View.extend ({
    subViews: [],

    initialize: function (options) {
        this.innerView = innerView;
    }

    render: function() {
      subViews[0] = new this.innerView();
    }    
  });

这样,在调用render之前,至少可以在测试中修改outerview.innerView。

此时,如果你觉得有必要,在initialize中实际注入依赖关系只是一个小小的额外步骤,可能使用默认值(this.innerView = options && options.innerView || innerView;)。