Как мы очищаем шпион программно в Жасмин? - PullRequest
71 голосов
/ 17 января 2012

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

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

Ответы [ 9 ]

117 голосов
/ 18 мая 2014

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

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

например

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

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

38 голосов
/ 19 июля 2012

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

spyOn($, 'ajax');

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

expect($.ajax).toHaveBeenCalled();

$.ajax.calls.reset()

expect($.ajax).not.toHaveBeenCalled();
19 голосов
/ 12 июня 2013

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

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

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

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

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

Чтобы восстановить исходный метод, сделайте это:

$.ajax.and.callThrough();
6 голосов
/ 17 января 2012

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

})

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

5 голосов
/ 08 марта 2017

Это сработало для меня в Jasmine 2.5, чтобы разрешить повторную настройку 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();
    });
}

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

1 голос
/ 28 июня 2016

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

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

})

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

0 голосов
/ 24 июня 2019

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

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

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

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

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

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

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

0 голосов
/ 09 мая 2018

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

mockedService.spiedMethod = null;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...