如何在单元测试时测试绑定函数的相等性?

时间:2015-12-16 09:09:00

标签: javascript unit-testing jasmine

我想测试传递给函数的参数是函数引用,但函数引用是使用bind()传递的。

考虑要测试的代码(为简洁起见缩短):

initialize: function () {
    this.register(this.handler.bind(this));
}

此单元测试用于检查是否register()调用了handler()

it('register handler', function () {
    spyOn(bar, 'register');
    bar.initialize();
    expect(bar.register.calls.argsFor(0)[0]).toEqual(bar.handler);
});

由于使用bind()的绑定函数,arg不等于我想的函数引用 - 如何在仍然使用bind()方法的同时测试正确的函数引用?

注意:这不是特定于茉莉花,我只是认为它是合适的,因为使用的方法。

4 个答案:

答案 0 :(得分:5)

而不是

expect(bar.register.calls.argsFor(0)[0]).toEqual(bar.handler);

你可以做到

expect(Object.create(bar.handler.prototype) instanceof bar.register.calls.argsFor(0)[0])
  .toBe(true);

expect(Object.create(bar.handler.prototype)).
  toEqual(jasmine.any(bar.register.calls.argsFor(0)[0]));

这是有效的,因为绑定函数的内部[[HasInstance]]方法委托给原始函数的[[HasInstance]]方法。

This blog post对绑定函数进行了更详细的分析。

答案 1 :(得分:1)

this.handler.bind(this)完全创建了一个新函数,因此它不等于bar.handler。 请参阅Function.prototype.bind()

您可以将有界函数作为参数传递给initialize函数,然后对其进行测试,例如:

var handler = bar.handler.bind(bar);
bar.initialize(handler);
expect(bar.register.calls.argsFor(0)[0]).toEqual(handler);

答案 2 :(得分:1)

我设法保留测试和代码并解决它。

我使用空的anon func监视函数引用,然后在监视寄存器方法时调用它 - 如果间谍被调用,我知道它传递了正确的引用。

it('register handler', function () {
    spyOn(bar, 'handler').and.callFake(function(){}); // do nothing
    spyOn(bar, 'register').and.callFake(function(fn){
        fn();
        expect(bar.handler).toHaveBeenCalled();
    });
    bar.initialize();
});

答案 3 :(得分:0)

我以为我会添加另一种对我来说不太尴尬的方法。

提供了类似的课程:

class Bar {
  public initialize() {
    this.register(this.handler.bind(this));
  }
  private register(callback) {}
  private handler() {}
}

完整规格如下:

describe('Bar', () => {
  let bar;

  beforeEach(() => {
    bar = new Bar();
  });

  describe('initialize', () => {
    let handlerContext;

    beforeEach(() => {
      bar.handler = function() {
        handlerContext = this;
      };
      bar.register = jest.fn(callback => {
        callback();
      });
      bar.initialize();
    });

    it('calls register with the handler', () => {
      expect(bar.register).toHaveBeenCalledWith(expect.any(Function));
    });

    it('handler is context bound', () => {
      expect(handlerContext).toEqual(bar);
    });
  });
});