我们如何以编程方式清除茉莉花测试套件中的间谍?感谢。
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
})
答案 0 :(得分:117)
将isSpy
设置为false
是一个非常糟糕的主意,因为那时你会侦察间谍,当Jasmine在你的规范结束时清除间谍时你就不会得到原始方法。
该方法将等于第一个间谍。
如果已经在监视一个方法并且你想要调用原始方法,那么你应该调用andCallThrough()
来覆盖第一个间谍行为。
例如
var spyObj = spyOn(obj,'methodName').andReturn(true);
spyObj.andCallThrough();
您可以致电this.removeAllSpies()
(this
- spec)
答案 1 :(得分:38)
我认为这是.reset()的用途:
spyOn($, 'ajax');
$.post('http://someUrl', someData);
expect($.ajax).toHaveBeenCalled();
$.ajax.calls.reset()
expect($.ajax).not.toHaveBeenCalled();
答案 2 :(得分:19)
所以间谍会在规格之间自动重置。
如果您在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!
答案 3 :(得分:9)
在Jasmine 2中,间谍状态保存在SpyStrategy实例中。
您可以通过调用$.ajax.and
来获取此实例。
请参阅the Jasmine source code on GitHub。
因此,要设置不同的假方法,请执行以下操作:
$.ajax.and.callFake(function() { ... });
要重置为原始方法,请执行以下操作:
$.ajax.and.callThrough();
答案 4 :(得分:6)
我不确定它是否是一个好主意,但你可以简单地将函数的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 :(得分: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();
});
}
然后你可以多次调用它而不会出错。 spyOnAjax(mock1); spyOnAjax(mock2);
答案 6 :(得分:1)
或者你可以做到
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 ..
答案 7 :(得分:1)
从jasmine 2.5开始,您可以使用此全局设置来更新测试用例中的间谍:
jasmine.getEnv().allowRespy(true);
答案 8 :(得分:0)
我要发布此答案以解决@ Tri-Vuong OP的代码中的评论-这是我访问此页面的主要原因:
我想在这里重写间谍...并做一些不同的操作
到目前为止,没有一个答案可以解决这一点,因此,我将发布所学内容并总结其他答案。
@Alissa解释了为什么将isSpy
设置为false
是一个坏主意时正确地调用了它-有效地监视了间谍,从而导致Jasmine的自动拆卸行为不再起作用。她的解决方案(放在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
-声明”先前存储在变量中的spyObj的新行为。 beforeEach()
。第一个测试说明了我这样做的用例-我希望间谍在大多数测试中表现出一定的行为,然后在以后的一些测试中对其进行更改。
对于早期版本的Jasmine,请将相应的调用分别更改为.andCallFake(
,.andCallThrough()
和.andReturnValue(
。
答案 9 :(得分:-1)
将spy方法设置为null
mockedService.spiedMethod = null;