我们如何在Jasmine中以编程方式清除间谍?

Tri*_*ong 72 javascript 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
})
Run Code Online (Sandbox Code Playgroud)

Ali*_*ssa 120

设置isSpyfalse是一个非常糟糕的主意,因为那么你窥视一个间谍,当茉莉花在你规范结尾清除间谍,你不会得到原来的方法.该方法将等于第一个间谍.

如果已经在监视一个方法并且你想要调用原始方法,你应该调用andCallThrough()哪个将覆盖第一个间谍行为.

例如

var spyObj = spyOn(obj,'methodName').andReturn(true);
spyObj.andCallThrough();
Run Code Online (Sandbox Code Playgroud)

你可以通过调用this.removeAllSpies()(this- spec)清除所有间谍

  • 请注意,在jasmine 2中它是spyObj.and.callThrough(); (19认同)
  • 如果您不想调用原始函数但只是覆盖嵌套描述的原始间谍,请使用"spyObj.and.returnValue('其他值')返回另一个值;" (4认同)
  • 使用新语法:`spyOn(obj,'methodName').and.returnValue(true);` 设置 spy 返回一个值。然后在进一步的测试中,您希望它像这样监视真正的函数:`obj.methodName.and.callThrough();` (2认同)

ugl*_*nky 38

我认为这就是.reset()的用途:

spyOn($, 'ajax');

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

expect($.ajax).toHaveBeenCalled();

$.ajax.calls.reset()

expect($.ajax).not.toHaveBeenCalled();
Run Code Online (Sandbox Code Playgroud)

  • 请注意,这已在Jasmine 2中更改为"mySpy.calls.reset()". (17认同)
  • 所以这一切都是重置跟踪状态,如果你想恢复默认行为,这将无济于事. (11认同)
  • 一个完全错误回答问题的答案怎么会有近40个赞成票?问题询问如何覆盖“andCallFake”,而不是如何重置呼叫计数器。 (2认同)

Fil*_*lmJ 20

间谍会在规格之间自动重置.

如果你andCallFake()在a中使用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!
Run Code Online (Sandbox Code Playgroud)


tit*_*usd 9

在Jasmine 2中,间谍状态保存在SpyStrategy实例中.你可以掌握这个实例调用$.ajax.and.请参阅GitHub上的Jasmine源代码.

因此,要设置不同的假方法,请执行以下操作:

$.ajax.and.callFake(function() { ... });
Run Code Online (Sandbox Code Playgroud)

要重置为原始方法,请执行以下操作:

$.ajax.and.callThrough();
Run Code Online (Sandbox Code Playgroud)

  • 我不认为`$ .ajax.and.andCallThrough();`是正确的.应该是`$ .ajax.and.callThrough();` (2认同)

Ham*_*eem 8

从 jasmine 2.5 开始,您可以使用此全局设置来更新测试用例中的间谍:

jasmine.getEnv().allowRespy(true);
Run Code Online (Sandbox Code Playgroud)


小智 5

这在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();
    });
}
Run Code Online (Sandbox Code Playgroud)

然后你可以多次调用它而不会出错.spyOnAjax(mock1); spyOnAjax(mock2);


And*_*rle -3

我不确定它是否是一个好主意但你可以简单地将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');
    })

})
Run Code Online (Sandbox Code Playgroud)

但也许最好为这种情况创建一个新的套件,你需要你间谍的其他行为.

  • 这不应该是接受的答案!请参阅@ Alissa的回答 (9认同)
  • 这真的不是一个好主意,这种方式在规范完成后运行方法将保持间谍而不是原来的方法看到Alissa的回答 (4认同)
  • 这不是一个好主意,请参阅我的回答。 (3认同)
  • 完美安德烈亚斯.正是我需要的.如果你后来弄清楚这是不是一个好主意.请告诉我.谢谢.+1 (2认同)