Question

Comment nettoyer l'espion dans une suite de tests de jasmin par programmation? Merci.

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
})
Était-ce utile?

La solution

Je ne sais pas si c'est une bonne idée mais vous pouvez simplement définir le isSpy Indicateur sur la fonction à false:

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');
    })

})

Mais peut-être que c'est une meilleure idée de créer une nouvelle suite pour ce cas où vous avez besoin d'un autre comportement de votre espion.

Autres conseils

paramètre isSpy à false est une très mauvaise idée, puisque vous vous espionnez sur un espion et lorsque Jasmine efface les espions à la fin de votre spécification, vous n'obtiendrez pas la méthode d'origine. La méthode sera égale au premier espion.

Si vous espionnez déjà une méthode et vous voulez que la méthode d'origine soit appelée à la place, vous devez appeler andCallThrough() qui remplacera le premier comportement d'espionnage.

par exemple

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

Vous pouvez effacer toutes les espions en appelant this.removeAllSpies() (this - spec)

Je pense que c'est ce .réinitialiser() est pour:

spyOn($, 'ajax');

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

expect($.ajax).toHaveBeenCalled();

$.ajax.calls.reset()

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

Ainsi, les espions sont réinitialisés automatiquement entre les spécifications.

Vous n'obtenez en fait pas l'avantage de la "restauration" de la fonction d'origine si vous utilisez andCallFake() dans un beforeEach() puis tentez de le changer de force dans une spécification (ce qui explique probablement pourquoi il essaie de vous empêcher de le faire).

Soyez donc prudent, surtout si votre espion est fixé sur un objet global comme jQuery.

Manifestation:

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!

Dans Jasmine 2, l'état d'espion est tenu dans une instance spystrategy. Vous pouvez vous procurer cette instance d'appel $.ajax.and. Voir le code source du jasmin sur github.

Donc, pour définir une fausse méthode différente, faites-le:

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

Pour réinitialiser la méthode d'origine, faites-le:

$.ajax.and.callThrough();

Cela a fonctionné pour moi dans Jasmine 2.5 pour permettre la réinstallation de Mock 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();
    });
}

Ensuite, vous pouvez l'appeler plusieurs fois sans erreur. Spyonajax (Mock1); SpyonaJax (Mock2);

Ou vous pouvez le faire

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');
    })

})

Dans ce cas, vous utilisez le même espion, mais changez simplement le VAR qu'il renverra.

Je publie cette réponse pour aborder le commentaire dans le code de OP @ Tri-Vuong - qui était ma principale raison de ma visite de cette page:

Je veux remplacer l'espion ... ici et le faire un peu différemment

Aucune des réponses ne traite jusqu'à présent de ce point, donc je publierai ce que j'ai appris et résume également les autres réponses.

@Alissa l'a appelé correctement quand elle a expliqué pourquoi c'est une mauvaise idée de définir isSpy à false - Espionnant efficacement un espion entraînant le comportement de l'auto-attitude du jasmin qui ne fonctionne plus comme prévu. Sa solution (placée dans le contexte OP et mise à jour pour Jasmine 2+) était la suivante:

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
})

Le dernier it Le test montre comment on pourrait changer le comportement d'un espion existant en quelque chose d'autre en plus du comportement original: "and-Carrière "Le nouveau comportement sur le SpyOBJ précédemment stocké dans la variable dans le beforeEach(). Le premier test illustre mon cas d'utilisation pour ce faire - je voulais qu'un espion se comporte d'une certaine manière pour la plupart des tests, mais ensuite le changer pour quelques tests plus tard.

Pour les versions antérieures du jasmin, modifiez les appels appropriés .andCallFake(, .andCallThrough(), et .andReturnValue( respectivement.

De Jasmine 2.5, vous pouvez utiliser ce paramètre global pour mettre à jour un espion dans vos cas de test:

jasmine.getEnv().allowRespy(true);

Il suffit de définir la méthode d'espion sur NULL

mockedService.spiedMethod = null;
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top