Как мы можем очистить шпиона программно в Жасмин?


как мы очищаем шпиона в наборе тестов jasmine программно? Спасибо.

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

8 ответов:

Я не уверен, что это хорошая идея, но вы можете просто установить isSpy флаг на функцию 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');
    })

})

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

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

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

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

вы можете очистить всех шпионов, позвонив this.removeAllSpies() (this - spec)

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

spyOn($, 'ajax');

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

expect($.ajax).toHaveBeenCalled();

$.ajax.calls.reset()

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

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

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

в Jasmine 2 состояние spy хранится в экземпляре SpyStrategy. Вы можете получить доступ к этому экземпляру вызова $.ajax.and. Смотрите исходный код жасмина на GitHub.

Итак, чтобы установить другой поддельный метод, сделайте это:

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

чтобы вернуться к исходному методу, выполните следующие действия:

$.ajax.and.callThrough();

это сработало для меня в 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);

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

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, который он вернет..

просто установите метод spy в null

mockedService.spiedMethod = null;