Подтвердить что ты не робот

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

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

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

Ответ 1

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

})

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

Ответ 2

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

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

например

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

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

Ответ 3

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

spyOn($, 'ajax');

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

expect($.ajax).toHaveBeenCalled();

$.ajax.calls.reset()

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

Ответ 4

Итак, шпионы автоматически reset между спецификациями.

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

Ответ 5

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

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

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

В reset к исходному методу сделайте следующее:

$.ajax.and.callThrough();

Ответ 6

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

Ответ 7

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

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

})

Ответ 8

Я отправляю этот ответ на адрес комментария в коде OP @Tri-Vuong, что и послужило моей основной причиной посещения этой страницы:

Я хочу переопределить шпиона... вот и сделай это немного по-другому

Ни один из ответов до сих пор не затронул этот вопрос, поэтому я опубликую то, что я узнал, и обобщу другие ответы.

@Alissa назвал это правильно, когда она объяснила, почему плохая идея установить isSpy в false - эффективно шпионить за шпионом, что приводит к автоматическому отключению Jasmine, который больше не функционирует, как предполагалось. Ее решение (помещенное в контекст OP и обновленное для Jasmine 2+) было следующим:

beforeEach(() => {
  var spyObj = spyOn(obj,'methodName').and.callFake(function(params){
  }) // @Alissa 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 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
})

Последний тест it демонстрирует, как можно изменить поведение существующего шпиона на что-то еще, кроме исходного поведения: " and -declare" новое поведение spyObj, ранее сохраненное в переменной в beforeEach(). Первый тест иллюстрирует мой вариант использования для этого - я хотел, чтобы шпион вел себя определенным образом в большинстве тестов, но затем изменил его на несколько тестов позже.

Для более ранних версий Jasmine измените соответствующие вызовы на .andCallFake(, .andCallThrough() и .andReturnValue( соответственно).

Ответ 9

В jasmine 2.5 вы можете использовать этот глобальный параметр для обновления шпиона в ваших тестовых примерах:

jasmine.getEnv().allowRespy(true);

Ответ 10

просто установите метод шпиона на ноль

mockedService.spiedMethod = null;