揭示模块替代或变化以进行测试

时间:2015-01-11 04:42:58

标签: javascript unit-testing design-patterns jasmine

概述

我已经使用了Revealing Module Pattern几个月了,我正在寻找这种模式的替代或变体来解决两个问题我的问题目前拥有事件处理程序和可测试性。我知道我可以拿出下面的一些组合来解决我的问题,但我希望找到一个可以持续使用的清洁替代方案,以解决我目前的两个问题。

揭示模块模式

所以在这个例子中,我对事件处理程序没有任何问题,但是我不能模拟对函数的调用 在功能内进行单独测试:

var Lion = (function () {

  // Reference to rawr works as expected when the click event is triggered
  function watch() {
    document.addEventListener('click', rawr);
  }

  function rawr() {
    console.log('rawr');
  }

  function attack() {
    console.log('attack');
  }

  /*
   * Can't test goCrazy() in isolation.  Mocking rawr() and attack()
   * has no effect as demonstrated below.
   */
  function goCrazy() {
    rawr();
    attack();

    // Important "crazy" logic
  }

  return {
    watch: watch,
    rawr: rawr,
    attack: attack,
    goCrazy: goCrazy
  };
}());

module.exports = Lion;

示例测试案例(Jasmine)

describe('Mock Check', function () {

  it('should mock rawr() and attack() and test only goCrazy logic', function () {
    var lion = require('Lion');

    spyOn(lion, 'rawr').and.reutrnValue(true);  
    spyOn(lion, 'attack').and.reutrnValue(true);  

    var crazy = lion.goCrazy();

    expect(lion.rawr).toHaveBeenCalled(); // <-- Fails
    expect(lion.attack).toHaveBeenCalled(); // <-- Fails

    // can't test goCrazy() logic in isolation :(
  });
});

使用this代替相同模块并使用new

调用

在此示例中,我可以成功模拟对函数内函数的调用,但如果我尝试添加事件处理程序,则在触发事件时this变为undefined

var Lion = function () {

  // Reference to 'this' becomes undefined when event is triggered
  this.watch = function () {
    document.addEventListener('click', this.rawr);
  }

  this.rawr = function () {
    console.log('rawr');
  }

  this.attack = function () {
    console.log('attack');
  }

  /*
   * Can successfully test goCrazy() in isolation by being able to mock 
   * rawr() and attack() as needed
   */
  this.goCrazy = function () {
    this.rawr();
    this.attack();

    // Important "crazy" logic
  }
};

module.exports = Lion;

示例测试案例(Jasmine)

describe('Mock Check', function () {

  it('should mock rawr() and attack() and test only goCrazy logic', function () {
    var Lion = require('Lion');
    var lion = new Lion();

    spyOn(lion, 'rawr').and.reutrnValue(true);  
    spyOn(lion, 'attack').and.reutrnValue(true);  

    var crazy = lion.goCrazy();

    expect(lion.rawr).toHaveBeenCalled(); // <-- Success
    expect(lion.attack).toHaveBeenCalled(); // <-- Success

    // testing goCrazy logic in isolation :)
  });
});

感谢您的时间。如果有必要澄清,请告诉我,我将修改我的帖子。

1 个答案:

答案 0 :(得分:1)

这里的实际问题是,事件处理程序丢失了当前对象的上下文。你可以像这样绑定它

document.addEventListener('click', this.rawr.bind(this));

这将确保无论何时调用rawrthis内的rawr都对应于您创建的lion对象。