web-dev-qa-db-ja.com

ジャスミンでプログラム的にスパイをクリアするにはどうすればよいですか?

ジャスミンテストスイートのスパイをプログラムでクリアするにはどうすればよいですか?ありがとう。

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
})
71
Tri Vuong

良いアイデアかどうかはわかりませんが、関数の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

isSpyfalseに設定するのは非常に悪い考えです。スパイをスパイし、仕様の最後でJasmineがスパイをクリアすると、元のメソッドを取得できなくなるからです。メソッドは最初のスパイに等しくなります。

すでにメソッドをスパイしていて、代わりに元のメソッドを呼び出す場合は、andCallThrough()を呼び出して、最初のスパイの動作をオーバーライドします。

例えば

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

this.removeAllSpies()this-spec)を呼び出すことで、すべてのスパイをクリアできます

118
Alissa

私はそれが 。reset() の目的だと思う:

spyOn($, 'ajax');

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

expect($.ajax).toHaveBeenCalled();

$.ajax.calls.reset()

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

そのため、スパイは仕様間で自動的にリセットされます。

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!
19
FilmJ

Jasmine 2では、スパイ状態はSpyStrategyインスタンスに保持されます。 $.ajax.andを呼び出してこのインスタンスを取得できます。 GitHubのJasmineソースコード を参照してください。

したがって、別の偽のメソッドを設定するには、次のようにします。

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

元の方法にリセットするには、次の操作を行います。

$.ajax.and.callThrough();
9
titusd

これは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);

5
user7054363

またはあなたはそれを行うことができます

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

})

この場合、同じスパイを使用しますが、返される変数を変更するだけです。

1
RafaCianci

Jasmine 2.5から、このグローバル設定を使用して、テストケース内のスパイを更新できます。

jasmine.getEnv().allowRespy(true);
0
Hamzeen Hameem

OP @ Tri-Vuongのコードのコメントに対処するために、この回答を投稿しています。これが、このページにアクセスする主な理由です。

私はスパイを無効にしたい...ここで、少し違ったやり方でやる

これまでのところ、この点に対処する回答はないため、これまでに学んだことを投稿し、他の回答も要約します。

@Alissaは、isSpyfalseに設定するのが悪い考えである理由を説明したときに、それを正しく呼び出しました。彼女のソリューション(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」は、以前にbeforeEach()。最初のテストは、これを行うためのユースケースを示しています。ほとんどのテストでスパイが特定の動作をするようにしたかったのですが、後でいくつかのテストでスパイを変更しました。

以前のバージョンのJasmineの場合、適切な呼び出しをそれぞれ_.andCallFake(_、.andCallThrough()、および_.andReturnValue(_に変更します。

0
LHM