Wie klären wir den Spion programmgesteuert in einer Jasmin-Testsuite? Vielen Dank.
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
})
javascript
jasmine
Tri Vuong
quelle
quelle
describe
oderit
Block, in dem er definiert ist, und wird nach jeder Spezifikation entfernt."Antworten:
Ich bin mir nicht sicher, ob es eine gute Idee ist, aber Sie können einfach das
isSpy
Flag für die Funktion auf false setzen: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'); }) })
Aber vielleicht ist es eine bessere Idee, eine neue Suite für diesen Fall zu erstellen, in dem Sie ein anderes Verhalten von Ihrem Spion benötigen.
quelle
Die Einstellung
isSpy
auffalse
ist eine sehr schlechte Idee, da Sie seitdem einen Spion ausspionieren und wenn Jasmine die Spione am Ende Ihrer Spezifikation löscht, erhalten Sie nicht die ursprüngliche Methode. Die Methode entspricht dem ersten Spion.Wenn Sie bereits eine Methode ausspionieren und stattdessen die ursprüngliche Methode aufgerufen werden soll, sollten Sie aufrufen,
andCallThrough()
wodurch das erste Spionageverhalten außer Kraft gesetzt wird.zum Beispiel
var spyObj = spyOn(obj,'methodName').andReturn(true); spyObj.andCallThrough();
Sie können alle Spione löschen, indem Sie
this.removeAllSpies()
(this
- spec) aufrufen.quelle
spyOn(obj,'methodName').and.returnValue(true);
Stellen Sie den Spion so ein, dass er einen Wert zurückgibt. Dann wollen Sie in einem weiteren Test, dass es die eigentliche Funktion wieobj.methodName.and.callThrough();
Ich denke, dafür ist .reset () gedacht :
spyOn($, 'ajax'); $.post('http://someUrl', someData); expect($.ajax).toHaveBeenCalled(); $.ajax.calls.reset() expect($.ajax).not.toHaveBeenCalled();
quelle
mySpy.calls.reset()
in Jasmine 2 geändert wurde.mySpy.calls.reset()
Setzt den Zähler zurück, zu dem der Spion gerufen wurde. Sie können es überprüfen mitexpect(spy).toHaveBeenCalledTimes(1)
andCallFake
und nicht zurückgesetzt werden soll.So werden Spione zwischen den Spezifikationen automatisch zurückgesetzt.
Sie erhalten tatsächlich nicht den Vorteil einer "Wiederherstellung" der ursprünglichen Funktion, wenn Sie sie
andCallFake()
innerhalb einer verwendenbeforeEach()
und dann versuchen, sie innerhalb einer Spezifikation zwangsweise zu ändern (was wahrscheinlich der Grund ist, warum versucht wird, Sie daran zu hindern).Seien Sie also vorsichtig, insbesondere wenn Ihr Spion auf ein globales Objekt wie jQuery eingestellt ist.
Demonstration:
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!
quelle
In Jasmine 2 wird der Spionagestatus in einer SpyStrategy-Instanz gespeichert. Sie können diesen Instanzaufruf erhalten
$.ajax.and
. Siehe den Jasmine-Quellcode auf GitHub .Um eine andere gefälschte Methode festzulegen, gehen Sie folgendermaßen vor:
$.ajax.and.callFake(function() { ... });
Gehen Sie folgendermaßen vor, um zur ursprünglichen Methode zurückzukehren:
quelle
$.ajax.and.andCallThrough();
es richtig ist. Sollte sein$.ajax.and.callThrough();
beforeEach
:spyOn(Foobar, 'getFoo').and.returnValue('generic'); }
dann innenit
:Foobar.getFoo.and.returnValue('special')
. Vielen Dank!Dies funktionierte für mich in Jasmine 2.5, um das Zurücksetzen von Mock Ajax zu ermöglichen.
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(); }); }
Dann können Sie es mehrmals ohne Fehler aufrufen. spyOnAjax (mock1); spyOnAjax (mock2);
quelle
Ab Jasmin 2.5 können Sie diese globale Einstellung verwenden, um einen Spion in Ihren Testfällen zu aktualisieren:
jasmine.getEnv().allowRespy(true);
quelle
Oder du kannst es schaffen
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'); }) })
In diesem Fall verwenden Sie denselben Spion, ändern jedoch nur die Variable, die zurückgegeben wird.
quelle
Ich poste diese Antwort, um den Kommentar im Code von OP @ Tri-Vuong zu adressieren - was mein Hauptgrund für meinen Besuch auf dieser Seite war:
Keine der bisherigen Antworten befasst sich mit diesem Punkt, daher werde ich das Gelernte veröffentlichen und auch die anderen Antworten zusammenfassen.
@Alissa nannte es richtig , wenn sie erklärt , warum es eine schlechte Idee, Satz ist
isSpy
zufalse
- effektiv auf einem Spion Spionage was in der Auto-Teardown Verhalten von Jasmin keine funktionierende länger als gedacht. Ihre Lösung (im OP-Kontext platziert und für Jasmine 2+ aktualisiert) war wie folgt:beforeEach(() => { var spyObj = spyOn(obj,'methodName').and.callFake(function(params){ }) // @Alissa's solution part a - store the spy in a variable }) it("should do the declared spy behavior", () => { // Act and assert as desired }) it("should do what it used to do", () => { spyObj.and.callThrough(); // @Alissa's solution part b - restore spy behavior to original function behavior // Act and assert as desired }) it("should do something a little differently", () => { spyObj.and.returnValue('NewValue'); // added solution to change spy behavior // Act and assert as desired })
Der letzte
it
Test zeigt, wie man das Verhalten eines vorhandenen Spions in etwas anderes als das ursprüngliche Verhaltenand
ändern kann : " -declare" das neue Verhalten auf dem spyObj, das zuvor in der Variablen in der gespeichert warbeforeEach()
. Der erste Test veranschaulicht meinen Anwendungsfall dafür - ich wollte, dass sich ein Spion für die meisten Tests auf eine bestimmte Weise verhält, aber später für einige Tests ändert.Für frühere Versionen von Jasmin, ändern Sie die entsprechenden Anrufe
.andCallFake(
,.andCallThrough()
und.andReturnValue(
jeweils.quelle
Setzen Sie einfach die Spionagemethode auf null
mockedService.spiedMethod = null;
quelle