我想测试传递给函数的参数是函数引用,但函数引用是使用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()
方法的同时测试正确的函数引用?
注意:这不是特定于茉莉花,我只是认为它是合适的,因为使用的方法。
答案 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);
});
});
});