2012-01-16 7 views
58

Как очистить шпион в наборе тестов жасмина программно? Благодарю.Как мы очищаем шпиона программно в Жасмине?

beforeEach(function() { 
    spyOn($, "ajax").andCallFake(function(params){ 
    }) 
}) 

it("should do something", function() { 
    //I want to override the spy on ajax here and do it a little differently 
}) 
+4

Несомненно, вы выбрали правильный «правильный» ответ? – hgoebl

+0

As of Jasmine 2.0 [«Шпион существует только в блоке' describe' или 'it', в котором он определен, и будет удален после каждого spec."] (Https://jasmine.github.io/2.0/ ознакомление.html # раздел-шпионы) – AJP

ответ

7

Я не уверен, если его хорошая идея, но вы можете просто установить isSpy флаг на функцию ложь:

describe('test', function() { 
    var a = {b: function() { 
    }}; 
    beforeEach(function() { 
     spyOn(a, 'b').andCallFake(function(params) { 
      return 'spy1'; 
     }) 
    }) 
    it('should return spy1', function() { 
     expect(a.b()).toEqual('spy1'); 
    }) 

    it('should return spy2', function() { 
     a.b.isSpy = false; 
     spyOn(a, 'b').andCallFake(function(params) { 
      return 'spy2'; 
     }) 
     expect(a.b()).toEqual('spy2'); 
    }) 

}) 

Но, возможно, его лучшая идея создать новый набор для этот случай, когда вам нужно другое поведение от вашего шпиона.

+2

Perfect Andreas. Только то, что мне нужно. Если позже вы выясните, хорошая идея или нет. Пожалуйста, дайте мне знать. Благодарю. +1 –

+0

это не отличная идея, см. Мой ответ. – FilmJ

+0

@ Андреас благодарит! Именно то, что мне нужно ... – zbynour

36

Я думаю, что это то, что .reset() для:

spyOn($, 'ajax'); 

$.post('http://someUrl', someData); 

expect($.ajax).toHaveBeenCalled(); 

$.ajax.calls.reset() 

expect($.ajax).not.toHaveBeenCalled(); 
+8

Итак, все это сбросит состояние отслеживания, если вы хотите восстановить поведение по умолчанию, это не поможет. – FilmJ

+14

Обратите внимание, что это изменилось на 'mySpy.calls.reset()' в Jasmine 2. –

16

Так шпионы автоматически сбрасываются между спецификациями.

Вы действительно не получаете преимущества «восстановления» исходной функции, если используете 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! 
+0

Я пытался выяснить, что мне нужно сделать, чтобы прекратить шпионаж на объект. Ваш ответ был очень ясным и полезным. И жасминовые камни автоматически заботятся о том, чтобы они срывали. – xverges

94

установка isSpy в false это очень плохая идея, так как тогда вы шпионить за шпион, и когда Жасмин очищает шпион в конце вашей спецификации вы не получите оригинальный метод , метод будет равен первому шпиону.

Если вы уже следите за методом и хотите, чтобы вместо него был вызван оригинальный метод, вы должны позвонить andCallThrough(), который переопределит первое поведение шпиона.

, например

var spyObj = spyOn(obj,'methodName').andReturn(true); 
spyObj.andCallThrough(); 

вы можете очистить все шпион по телефону this.removeAllSpies() (this - спецификация)

+0

Спасибо, это работает! – dbrin

+0

Это imho лучшее решение. –

+0

Я предпочитаю сказать, что настройка isSpy на false - это плохая вещь. Мне нравится, как Андреас К из соображений. – KSev

8

В жасмине 2, состояние шпионского проводятся в случае SpyStrategy. Вы можете получить этот экземпляр, вызывающий $.ajax.and. См. the Jasmine source code on GitHub.

Таким образом, чтобы установить другой фальшивый метод, это сделать:

$.ajax.and.callFake(function() { ... }); 

Для сброса к исходному методу, сделайте следующее:

$.ajax.and.callThrough(); 
+1

Я не думаю, что '$ .ajax.and.andCallThrough();' правильный , Должно быть '$ .ajax.and.callThrough();' – kriskodzi

+0

Это сработало для меня; внутри 'beforeEach':' spyOn (Foobar, 'getFoo'). and.returnValue ('generic'); } 'then inside' it': 'Foobar.getFoo.and.returnValue ('special')'. Благодаря! –

0

Или вы можете сделать это

describe('test', function() { 
 
    var a, c; 
 
    c = 'spy1'; 
 
    a = { 
 
     b: function(){} 
 
    }; 
 

 
    beforeEach(function() { 
 
     spyOn(a, 'b').and.callFake(function() { 
 
      return c; 
 
     }); 
 
    }) 
 

 
    it('should return spy1', function() { 
 
     expect(a.b()).toEqual('spy1'); 
 
    }) 
 

 
    it('should return spy2', function() { 
 
     c = 'spy2'; 
 
     expect(a.b()).toEqual('spy2'); 
 
    }) 
 

 
})

В этом случае вы используете тот же шпион, но просто измените var, который он вернет.

3

Это сработало для меня в Jasmine 2.5, чтобы разрешить повторную установку макета ajax.

function spyOnAjax(mockResult) { 
    // must set to true to allow multiple calls to spyOn: 
    jasmine.getEnv().allowRespy(true); 

    spyOn($, 'ajax').and.callFake(function() { 
     var deferred = $.Deferred(); 
     deferred.resolve(mockResult); 
     return deferred.promise(); 
    }); 
} 

Тогда вы можете позвонить ему несколько раз без ошибок. spyOnAjax (mock1); spyOnAjax (mock2);

Смежные вопросы