Как мы очищаем шпиона программно в Жасмине?
Как мы очищаем шпиона в тестовом наборе жасмина программным путем? Спасибо.
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
})
Ответы
Ответ 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;