[英]How can I test for equality to a bound function when unit testing?
我想测试传递给函数的参数是否是函数引用,但函数引用是使用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()
方法的同时测试是否传递了正确的函数引用?
注意:这不是茉莉花特有的,我只是因为所使用的方法而认为它是合适的。
代替
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.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);
我设法保留了测试和代码并解决了它。
我用一个空的匿名函数监视函数引用,然后在监视 register 方法时调用它 - 如果调用了 spy,我知道它传递了正确的引用。
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();
});
就我而言(使用jest ),我只是模拟了我想要的函数的 bind 实现,并对其进行了调整,使其返回原始函数而不是它的绑定副本。
具体来说,这是我尝试和工作的:
待测试代码:
// module test.js
export const funcsToExecute = [];
function foo(func) {
funcsToExecute.push(func);
}
export function bar(someArg) {
// bar body
}
export function run(someArg) {
foo(bar.bind(null, someArg));
}
我想断言在调用run
时, funcsToExecute
包含bar
所以我写了这样的测试:
import * as test from 'test';
it('should check that "funcsToExecute" contain only "bar"', () => {
jest.spyOn(test.bar, 'bind').mockImplementation((thisVal, ...args) => test.bar);
test.run(5);
expect(test.funcsToExecute.length).toBe(1);
expect(test.funcsToExecute[0]).toBe(test.bar);
});
对于你的例子,我想它会是这样的:
it('register handler', function () {
spyOn(bar, 'register');
spyOn(bar.handler, 'bind').mockImplementation((thisVal, ...args) => bar.handler);
bar.initialize();
expect(bar.register.calls.argsFor(0)[0]).toBe(bar.handler);
});
虽然我没有测试过。
我想我会添加另一种对我来说不那么尴尬的方法。
给定一个类,如:
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);
});
});
});
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.