Un modo per modificare le spie di Jasmine basate su argomenti?


147

Ho una funzione che vorrei testare che chiama due volte un metodo API esterno, utilizzando parametri diversi. Vorrei deridere questa API esterna con una spia Jasmine e restituire cose diverse in base ai parametri. C'è un modo per farlo in Jasmine? Il meglio che posso inventare è un hack con 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;
      }
    });
  });
});

Risposte:


215

Nelle versioni Jasmine 3.0 e successive è possibile utilizzare 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);
  });
});

Per le versioni di Jasmine precedenti alla 3.0 callFakeè la strada giusta da percorrere, ma è possibile semplificarlo utilizzando un oggetto per contenere i valori restituiti

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

A seconda della versione di Jasmine, la sintassi è leggermente diversa:

  • 1.3.1: .andCallFake(fn)
  • 2.0: .and.callFake(fn)

risorse:


11
Questo è ora and.callFake- jasmine.github.io/2.2/… >
Lucy Bain

Ho dovuto restituire diverse promesse, quindi il ritorno sembrava leggermente diverso: return q.when (params [myParam]) ;. Altrimenti, questo era un punto sulla soluzione al mio problema. La soluzione dei miei sogni sarebbe quella di cambiare le chiamate "and.returnValue".
Bill Turner,

7
sembra che il gelsomino dovrebbe avere un modo migliore di dichiararlo. Mi piace spyOn(fake, 'method').withArgs('abc').and.returnValue('Jane')e spyOn(fake, 'method').withArgs('123').and.returnValue(98765).
jrharshath,

@jrharshath .withArgsnon funziona per me in jasmine 2.0
hemkaran_raghav

1
.withArgsnon è realmente disponibile - intendevo dire che un tale metodo avrebbe senso quando si scrivono i test.
jrharshath,

9

Puoi anche usare $provideper creare una spia. E deridere usando and.returnValuesinvece di and.returnValuepassare dati parametrizzati.

Secondo i documenti di Jasmine: concatenando la spia con and.returnValues, tutte le chiamate alla funzione restituiranno valori specifici in ordine fino a quando non raggiunge la fine dell'elenco dei valori di ritorno, a quel punto tornerà indefinito per tutte le chiamate successive.

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

Questa è la risposta corretta, dal momento che un test dovrebbe sempre sapere esattamente come verrà chiamata una spia, e quindi dovrebbe semplicemente usare returnValuesper supportare più chiamate
Schmuli

2
Giusto per chiarire la risposta di akhouri: questo metodo funziona solo quando externalApi.get.and.returnValues('abc','123')viene chiamato all'interno della itfunzione. Altrimenti se si imposta un elenco di valori, altrimenti dove, non funzionerà mai perché l'ordine in cui vengono eseguiti i test non è prevedibile. In effetti i test non dovrebbero dipendere dall'ordine in cui vengono eseguiti.
avi.elkharrat,

0

Nel mio caso, avevo un componente che stavo testando e, nel suo costruttore, c'è un servizio di configurazione con un metodo chiamato getAppConfigValue che viene chiamato due volte, ogni volta con argomenti diversi:

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

Nelle mie specifiche, ho fornito ConfigService nel TestBed in questo modo:

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

Quindi, purché la firma per getAppConfigValue sia la stessa specificata nell'attuale ConfigService, ciò che la funzione fa internamente può essere modificato.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.