Любой способ изменить шпионов Жасмин на основе аргументов?

147

У меня есть функция, которую я хотел бы проверить, которая дважды вызывает метод внешнего API, используя разные параметры. Я хотел бы издеваться над внешним API с помощью шпионского жасмина и возвращать разные вещи в зависимости от параметров. Есть ли способ сделать это в Жасмин? Лучшее, что я могу придумать, это взломать с помощью andCallFake:

var functionToTest = function() {
  var userName = externalApi.get('abc');
  var userId = externalApi.get('123');
};


describe('my fn', function() {
  it('gets user name and ID', function() {
    spyOn(externalApi, 'get').andCallFake(function(myParam) {
      if (myParam == 'abc') {
        return 'Jane';
      } else if (myParam == '123') {
        return 98765;
      }
    });
  });
});
JMR
источник

Ответы:

215

В версии Jasmine 3.0 и выше вы можете использовать withArgs

describe('my fn', function() {
  it('gets user name and ID', function() {
    spyOn(externalApi, 'get')
      .withArgs('abc').and.returnValue('Jane')
      .withArgs('123').and.returnValue(98765);
  });
});

Для версий Jasmine ранее 3.0 callFakeэто правильный путь, но вы можете упростить его, используя объект для хранения возвращаемых значений

describe('my fn', function() {
  var params = {
    'abc': 'Jane', 
    '123': 98765
  }

  it('gets user name and ID', function() {
    spyOn(externalApi, 'get').and.callFake(function(myParam) {
     return params[myParam]
    });
  });
});

В зависимости от версии Jasmine, синтаксис немного отличается:

  • 1.3.1: .andCallFake(fn)
  • 2,0: .and.callFake(fn)

Ресурсы:

Андреас Кёберле
источник
11
Это сейчас and.callFake- jasmine.github.io/2.2/… >
Люси Бэйн
Мне пришлось вернуть разные обещания, поэтому возвращение выглядело немного иначе: return q.when (params [myParam]) ;. В противном случае, это было место для решения моей проблемы. Моим мечтой было бы изменить вызовы "and.returnValue".
Билл Тернер
7
чувствует, что у жасмина должен быть лучший способ объявить это. Вроде spyOn(fake, 'method').withArgs('abc').and.returnValue('Jane')и spyOn(fake, 'method').withArgs('123').and.returnValue(98765).
jrharshath
@jrharshath .withArgsне работает для меня в Жасмин 2.0
hemkaran_raghav
1
.withArgsна самом деле не доступно - я имел в виду, что такой метод будет иметь смысл при написании тестов.
Джаршат
9

Вы также можете использовать $provideдля создания шпиона. И использовать макет and.returnValuesвместо того, and.returnValueчтобы передавать параметризованные данные.

Согласно документам Jasmine: при соединении шпиона со and.returnValuesвсеми вызовами функции будут возвращаться определенные значения по порядку, пока он не достигнет конца списка возвращаемых значений, после чего он будет возвращать неопределенный для всех последующих вызовов.

describe('my fn', () => {
    beforeEach(module($provide => {
        $provide.value('externalApi', jasmine.createSpyObj('externalApi', ['get']));
    }));

        it('get userName and Id', inject((externalApi) => {
            // Given
            externalApi.get.and.returnValues('abc','123');

            // When
            //insert your condition

            // Then
            // insert the expectation                
        }));
});
akhouri
источник
Это правильный ответ, так как тест всегда должен точно знать, как будет вызываться шпион, и поэтому должен просто использовать его returnValuesдля поддержки нескольких вызовов
Шмули
2
Просто чтобы уточнить ответ Ахури: этот метод работает только тогда, когда externalApi.get.and.returnValues('abc','123')вызывается внутри itфункции. В противном случае, если вы установите список значений, иначе где, он никогда не будет работать, потому что порядок выполнения тестов не предсказуем. На самом деле тесты не должны зависеть от порядка их выполнения.
avi.elkharrat
0

В моем случае у меня был компонент, который я тестировал, и в его конструкторе есть служба конфигурации с методом getAppConfigValue, который вызывается дважды, каждый раз с разными аргументами:

constructor(private configSvc: ConfigService) {
  this.configSvc.getAppConfigValue('a_string');
  this.configSvc.getAppConfigValue('another_string');
}

В моей спецификации я предоставил ConfigService в TestBed следующим образом:

{
  provide: ConfigService,
  useValue: {
    getAppConfigValue: (key: any): any {
      if (key === 'a_string) {
        return 'a_value';
      } else if (key === 'another_string') {
        return 'another_value';
      }
    }
  } as ConfigService
}

Таким образом, до тех пор, пока подпись для getAppConfigValue будет такой же, как указано в фактическом ConfigService, то, что функция делает внутри, может быть изменено.

Гильермо
источник