试图监视 (Jasmine) Array.prototype 方法会导致堆栈溢出
Trying to spy (Jasmine) on Array.prototype methods causes stack overflow
这很奇怪。将 testem
runner 与 jasmine2
一起使用并执行以下规范(尽管它正确地标记了没有期望):
describe('Spying on array.prototype methods', function(){
it('should work this way', function(){
spyOn( Array.prototype, 'push' ).and.callThrough();
// expect(1).toBe(1);
});
});
但是,添加一个 expect
(任何 expect
!),它会导致堆栈溢出,并在 testem
控制台中显示以下消息:RangeError: Maximum call stack size exceeded. at http://localhost:7357/testem/jasmine2.js, line 980
html 报告页面达到规范然后挂起,没有显示任何实际结果。
最终我想做这样的事情:
describe('Some structure.method', function(){
it('does not use native push', function(){
spyOn( Array.prototype, 'push' ).and.callThrough();
[].push(1); // actually more like `myStructure.myMethod('test')`
expect( Array.prototype.push ).not.toHaveBeenCalled();
});
});
提前感谢任何可以阐明这一怪事的人。我可以不窥探原生原型方法吗?
当你监视某些东西时,jasmine 会创建一个包装器以跟踪该函数的调用。在这里,当您监视原型方法时,基本上甚至 jasmine 中的 push 操作本身也会调用间谍而不是数组上的实际 push 方法,这会导致无限循环。
当您调用 [].push(1)
时,它实际上 calls the tracker 如下所示:
spy = function() {
callTracker.track({ //<-- Calls tracker to track invocation
object: this,
args: Array.prototype.slice.apply(arguments)
});
依次调用调用跟踪器和 pushes the call context 到其内部跟踪器数组并进入递归循环,直到调用堆栈爆裂。
this.track = function(context) {
calls.push(context); //Now this again calls the spy
};
相反,如果你监视数组实例上的方法,你不会有这个问题,因为它为 that 数组实例的推送 属性 创建了一个间谍包装器(或者换句话说,该实例的 push
持有的引用(当前从 Array 原型继承)被 jasmine 创建的间谍的新函数引用覆盖):示例:
it('does not use native push', function(){
var arr = [];
spyOn(arr, 'push' ).and.callThrough();
arr.push(1);
expect(arr.push).toHaveBeenCalledWith(1);
});
但作为一个真实的用例(至少我从来没有这样做过),您总是可以检查目标数组的长度,并在特定操作后获取要比较的最后一项。您可能永远不需要监视本机方法(至少不是数组 :)),而是针对您感兴趣的对象进行测试并监视那些目标方法。
这很奇怪。将 testem
runner 与 jasmine2
一起使用并执行以下规范(尽管它正确地标记了没有期望):
describe('Spying on array.prototype methods', function(){
it('should work this way', function(){
spyOn( Array.prototype, 'push' ).and.callThrough();
// expect(1).toBe(1);
});
});
但是,添加一个 expect
(任何 expect
!),它会导致堆栈溢出,并在 testem
控制台中显示以下消息:RangeError: Maximum call stack size exceeded. at http://localhost:7357/testem/jasmine2.js, line 980
html 报告页面达到规范然后挂起,没有显示任何实际结果。
最终我想做这样的事情:
describe('Some structure.method', function(){
it('does not use native push', function(){
spyOn( Array.prototype, 'push' ).and.callThrough();
[].push(1); // actually more like `myStructure.myMethod('test')`
expect( Array.prototype.push ).not.toHaveBeenCalled();
});
});
提前感谢任何可以阐明这一怪事的人。我可以不窥探原生原型方法吗?
当你监视某些东西时,jasmine 会创建一个包装器以跟踪该函数的调用。在这里,当您监视原型方法时,基本上甚至 jasmine 中的 push 操作本身也会调用间谍而不是数组上的实际 push 方法,这会导致无限循环。
当您调用 [].push(1)
时,它实际上 calls the tracker 如下所示:
spy = function() {
callTracker.track({ //<-- Calls tracker to track invocation
object: this,
args: Array.prototype.slice.apply(arguments)
});
依次调用调用跟踪器和 pushes the call context 到其内部跟踪器数组并进入递归循环,直到调用堆栈爆裂。
this.track = function(context) {
calls.push(context); //Now this again calls the spy
};
相反,如果你监视数组实例上的方法,你不会有这个问题,因为它为 that 数组实例的推送 属性 创建了一个间谍包装器(或者换句话说,该实例的 push
持有的引用(当前从 Array 原型继承)被 jasmine 创建的间谍的新函数引用覆盖):示例:
it('does not use native push', function(){
var arr = [];
spyOn(arr, 'push' ).and.callThrough();
arr.push(1);
expect(arr.push).toHaveBeenCalledWith(1);
});
但作为一个真实的用例(至少我从来没有这样做过),您总是可以检查目标数组的长度,并在特定操作后获取要比较的最后一项。您可能永远不需要监视本机方法(至少不是数组 :)),而是针对您感兴趣的对象进行测试并监视那些目标方法。