使用 Jasmine 在 AngularJS 中测试去抖函数从不调用该函数

Posted

技术标签:

【中文标题】使用 Jasmine 在 AngularJS 中测试去抖函数从不调用该函数【英文标题】:Testing a debounced function in AngularJS with Jasmine never calls the function 【发布时间】:2016-04-02 19:03:53 【问题描述】:

我在使用下划线去抖动的服务中有一个方法。

该方法内部是对不同服务上的方法的调用。我正在尝试测试是否调用了不同的服务。

在我尝试测试去抖动方法时,从未调用不同服务的方法,并且 jasmine 失败并显示:

“预期的间谍 aMethod 已被调用。”

我知道它被调用(它在 chrome 中记录到控制台),它只是在期望已经失败之后才被调用。

所以...(最好)不添加 Sinon 或其他依赖项并且使用 给予解决方案的奖励积分*不必将 _.debounce 变成 $timeout...

怎么做?

angular.module('derp', [])
.service('herp', function() 
   return 
     aMethod: function() 
       console.log('called!'); 
       return 'blown'; 
     
   ; 
 )
 .service('Whoa', ['herp', function(herp)
   function Whoa()
     var that = this;
     this.mindStatus = 'meh';
     this.getMind = _.debounce(function()
       that.mindStatus = herp.aMethod();
     , 300);
   
   return Whoa;
 ]);

测试:

describe('Whoa', function()
  var $injector, whoa, herp;

  beforeEach(function()
    module('derp');
    inject(function(_$injector_)
      var Whoa;
      $injector = _$injector_;
      Whoa = $injector.get('Whoa');
      herp = $injector.get('herp');
      whoa = new Whoa();
    );
  );

  beforeEach(function()
    spyOn(herp, 'aMethod').andCallThrough();
  );

  it('has a method getMind, that calls herp.aMethod', function()
    whoa.getMind();
    expect(herp.aMethod).toHaveBeenCalled();
  );
);

为什么 AngularJS 测试之神抛弃了我?

* 我不知道如何在 *** 上给出实际的奖励积分,但如果可能的话,我会的。

【问题讨论】:

【参考方案1】:

我的去抖函数接受了参数,所以我像这样嘲笑_.debounce

spyOn(_, 'debounce').and.callFake(function(cb) return cb);

(对@Wawy 的回答稍作修改)

【讨论】:

【参考方案2】:

你只需要模拟 lodash debounce 方法:

describe('Whoa', function()
  var $injector, whoa, herp;

  beforeEach(function()
    module('derp');
    spyOn(_, 'debounce').and.callFake(function(cb)  return function()  cb();  );
    inject(function(_$injector_)
      var Whoa;
      $injector = _$injector_;
      Whoa = $injector.get('Whoa');
      herp = $injector.get('herp');
      whoa = new Whoa();
    );
  );

  beforeEach(function()
    spyOn(herp, 'aMethod').andCallThrough();
  );

  it('has a method getMind, that calls herp.aMethod', function()
    whoa.getMind();
    expect(herp.aMethod).toHaveBeenCalled();
  );
);

【讨论】:

不。还是行不通。在我们的两种情况下,都调用了 herp.aMethod,但在期望之前都没有调用。 我希望我现在能像承诺的那样拥有柴。 “最终”会解决这个问题。 在callfake里面的匿名函数里面放一个断点,然后检查堆栈看看它是从哪里调用的。 模拟函数真的被调用了吗? @AndrewLuhring 我已经编辑了我的答案。我现在意识到为什么它不起作用,在注入器实例化您的服务之后间谍正在完成,所以为时已晚。现在,它应该可以工作了。【参考方案3】:

Angular $timeout 在测试中具有优势,因为它在测试中被模拟为同步。当使用第三方异步工具时,不会有这个优势。一般来说,异步规范看起来像这样:

var maxDelay = 500;

  ...
  it('has a method getMind, that calls herp.aMethod', function (done)
    whoa.getMind();
    setTimeout(function () 
      expect(herp.aMethod).toHaveBeenCalled();
      done();
    , maxDelay);
  );

由于 Underscore debounce 不提供 flush 功能(而最新版本的 Lodash debounce does),异步测试是最好的选择。

【讨论】:

以上是关于使用 Jasmine 在 AngularJS 中测试去抖函数从不调用该函数的主要内容,如果未能解决你的问题,请参考以下文章

在 Jasmine 单元测试中模拟 AngularJS 模块依赖项

使用 Jasmine 在 AngularJS 中测试去抖函数从不调用该函数

Chutzpah - 使用 jasmine 和 TypeScript 进行 AngularJS 测试

使用 Jasmine 对包含私有超时的单元测试 Angularjs 指令

使用 yeoman 的 ReSharper Jasmine AngularJS 单元测试

jasmine matcher函数不在angularjs / karma单元测试中加载