[英]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.