Так шпионы автоматически сбрасываются между спецификациями.
Вы действительно не получаете преимущества «восстановления» исходной функции, если используете andCallFake()
в пределах beforeEach()
, а затем попытаетесь принудительно изменить его в спецификации (что, скорее всего, оно пытается помешать вам сделать это) ,
Так что будьте осторожны, особенно если ваш шпион установлен на глобальном объекте, таком как jQuery.
Демонстрация:
var a = {b:function() { return 'default'; } }; // global scope (i.e. jQuery)
var originalValue = a.b;
describe("SpyOn test", function(){
it('should return spy1', function(){
spyOn(a, 'b').andCallFake(function(params) {
return 'spy1';
})
expect(a.b()).toEqual('spy1');
});
it('should return default because removeAllSpies() happens in teardown', function(){
expect(a.b()).toEqual('default');
});
it('will change internal state by "forcing" a spy to be set twice, overwriting the originalValue', function(){
expect(a.b()).toEqual('default');
spyOn(a, 'b').andCallFake(function(params) {
return 'spy2';
})
expect(a.b()).toEqual('spy2');
// This forces the overwrite of the internal state
a.b.isSpy = false;
spyOn(a, 'b').andCallFake(function(params) {
return 'spy3';
})
expect(a.b()).toEqual('spy3');
});
it('should return default but will not', function(){
expect(a.b()).toEqual('default'); // FAIL
// What's happening internally?
expect(this.spies_.length).toBe(1);
expect(this.spies_[0].originalValue).toBe(originalValue); // FAIL
});
});
describe("SpyOn with beforeEach test", function(){
beforeEach(function(){
spyOn(a, 'b').andCallFake(function(params) {
return 'spy1';
})
})
it('should return spy1', function(){
// inspect the internal tracking of spies:
expect(this.spies_.length).toBe(1);
expect(this.spies_[0].originalValue).toBe(originalValue);
expect(a.b()).toEqual('spy1');
});
it('should return spy2 when forced', function(){
// inspect the internal tracking of spies:
expect(this.spies_.length).toBe(1);
expect(this.spies_[0].originalValue).toBe(originalValue);
// THIS EFFECTIVELY changes the "originalState" from what it was before the beforeEach to what it is now.
a.b.isSpy = false;
spyOn(a, 'b').andCallFake(function(params) {
return 'spy2';
})
expect(a.b()).toEqual('spy2');
});
it('should again return spy1 - but we have overwritten the original state, and can never return to it', function(){
// inspect the internal tracking of spies:
expect(this.spies_.length).toBe(1);
expect(this.spies_[0].originalValue).toBe(originalValue); // FAILS!
expect(a.b()).toEqual('spy1');
});
});
// If you were hoping jasmine would cleanup your mess even after the spec is completed...
console.log(a.b == originalValue) // FALSE as you've already altered the global object!
Несомненно, вы выбрали правильный «правильный» ответ? – hgoebl
As of Jasmine 2.0 [«Шпион существует только в блоке' describe' или 'it', в котором он определен, и будет удален после каждого spec."] (Https://jasmine.github.io/2.0/ ознакомление.html # раздел-шпионы) – AJP