Come spiare una proprietà di valore (piuttosto che un metodo) con Jasmine


115

Jasmine spyOnè utile per modificare il comportamento di un metodo, ma esiste un modo per modificare una proprietà di valore (piuttosto che un metodo) per un oggetto? il codice potrebbe essere come di seguito:

spyOn(myObj, 'valueA').andReturn(1);
expect(myObj.valueA).toBe(1);

Risposte:


97

Nel febbraio 2017, hanno unito un PR aggiungendo questa funzione, che hanno rilasciato nell'aprile 2017.

quindi per spiare i getter / setter usi: const spy = spyOnProperty(myObj, 'myGetterName', 'get'); dove myObj è la tua istanza, 'myGetterName' è il nome di quello definito nella tua classe come get myGetterName() {}e il terzo parametro è il tipo geto set.

Puoi usare le stesse affermazioni che usi già con le spie create con spyOn.

Quindi puoi ad esempio:

const spy = spyOnProperty(myObj, 'myGetterName', 'get'); // to stub and return nothing. Just spy and stub.
const spy = spyOnProperty(myObj, 'myGetterName', 'get').and.returnValue(1); // to stub and return 1 or any value as needed.
const spy = spyOnProperty(myObj, 'myGetterName', 'get').and.callThrough(); // Call the real thing.

Ecco la riga nel codice sorgente di GitHub in cui questo metodo è disponibile se sei interessato.

https://github.com/jasmine/jasmine/blob/7f8f2b5e7a7af70d7f6b629331eb6fe0a7cb9279/src/core/requireInterface.js#L199

Rispondendo alla domanda originale, con jasmine 2.6.1, potresti:

const spy = spyOnProperty(myObj, 'valueA', 'get').andReturn(1);
expect(myObj.valueA).toBe(1);
expect(spy).toHaveBeenCalled();

7
Come posso fare se valueAè un Observableo Subject? Sto ottenendoProperty valueA does not have access type get
Ka Mok

4
Ciò probabilmente significa che non puoi usarlo su quella proprietà. spyOnProperty sta usando getOwnPropertyDescriptor e sta controllando se il tipo di accesso get | set per quel descrittore di proprietà esiste. L'errore che ricevi è perché il descrittore di proprietà non è impostato o non ottiene per la proprietà che stai tentando di spiare. Jasmine fa questo: const descriptor = Object.getOwnPropertyDescriptor ... if (! Descriptor [accessType]) {// viene generato un errore}
Juan

Quindi, non c'è modo di spiare una proprietà senza espliciti metodi getter e setter? Spiare è una proprietà usata.
Dominik

@Dominik Qui ho scritto tutte le cose sotto il cofano relative a questo in un articolo più lungo: medium.com/@juanlizarazo/…
Juan

1
@ Mathieu non è una buona affermazione perché afferma solo ciò che sappiamo già da ciò che abbiamo detto alla spia di fare, ma è proprio quello che stavano chiedendo e il loro stesso frammento di codice della domanda ¯_ (ツ) _ / ¯ Il punto della loro domanda era come spiare una proprietà e non tanto il loro esempio specifico.
Juan

12

C'è qualche motivo per cui non puoi cambiarlo direttamente sull'oggetto? Non è come se javascript imponga la visibilità di una proprietà su un oggetto.


1
usare spyOnesplicitamente indica che voglio deridere qualcosa, mentre imposto direttamente la proprietà indica implicitamente che voglio deridere qualcosa e non sono sicuro che qualcun altro capirà che sto prendendo in giro qualcosa mentre legge il codice. Un altro caso è che non voglio cambiare il comportamento interno dell'oggetto, ad esempio se cambio la proprietà length per un array, l'array viene tagliato, quindi una simulazione sarà migliore
Shuping

@ Shuping, in questo caso, non saresti beffardo. Saresti stubbing, il che è perfettamente a posto. Dovresti "cambiare il comportamento" solo all'interno del test, che è ciò che stavi cercando di ottenere con spyOn.
Fabio Milheiro

Forse vuoi spiare il prototipo dell'oggetto runtime per assicurarti che la proprietà esista in runtime. Jasmine spyOnfallisce il test se la proprietà non esiste.
sennett

2
Un esempio è impostare o eliminare window.sessionStorage:TypeError: Cannot assign to read only property 'sessionStorage' of object '#<Window>'
Chris Sattinger,

2
Non è sempre possibile riassegnare la proprietà di un oggetto in javascript
Renaud

12

Jasmine non ha questa funzionalità, ma potresti essere in grado di hackerare qualcosa insieme usando Object.defineProperty.

Potresti effettuare il refactoring del codice per utilizzare una funzione getter, quindi spiare il getter.

spyOn(myObj, 'getValueA').andReturn(1);
expect(myObj.getValueA()).toBe(1);

Sì, è quello che posso fare per ora.
Shuping

4
per jasmine 2 è:and.returnValue(1)
jtzero

9

Il modo migliore è usare spyOnProperty. Prevede 3 parametri e devi passare geto setcome terzo parametro.

Esempio

const div = fixture.debugElement.query(By.css('.ellipsis-overflow'));
// now mock properties
spyOnProperty(div.nativeElement, 'clientWidth', 'get').and.returnValue(1400);
spyOnProperty(div.nativeElement, 'scrollWidth', 'get').and.returnValue(2400);

Qui sto impostando il getdi clientWidthdi div.nativeElementoggetto.


6

Se stai usando ES6 (Babel) o TypeScript puoi bloccare la proprietà usando le funzioni di accesso get e set

export class SomeClassStub {
  getValueA = jasmine.createSpy('getValueA');
  setValueA = jasmine.createSpy('setValueA');
  get valueA() { return this.getValueA(); }
  set valueA(value) { this.setValueA(value); }
}

Quindi nel tuo test puoi verificare che la proprietà sia impostata con:

stub.valueA = 'foo';

expect(stub.setValueA).toHaveBeenCalledWith('foo');

Oppure, se i getter fanno parte della classe sotto test, gli stub potrebbero essere iniettati in una sottoclasse.
ccprog

6

Il modo giusto per farlo è con la spia della proprietà, che ti permetterà di simulare una proprietà su un oggetto con un valore specifico.

const spy = spyOnProperty(myObj, 'valueA').and.returnValue(1);
expect(myObj.valueA).toBe(1);
expect(spy).toHaveBeenCalled();

1

Supponiamo che esista un metodo come questo che necessita di test. La srcproprietà dell'immagine minuscola deve essere verificata

function reportABCEvent(cat, type, val) {
                var i1 = new Image(1, 1);
                var link = getABC('creosote');
                    link += "&category=" + String(cat);
                    link += "&event_type=" + String(type);
                    link += "&event_value=" + String(val);
                    i1.src = link;
                }

SpyOn () di seguito fa sì che la "nuova immagine" riceva il codice falso dal test il codice spyOn restituisce un oggetto che ha solo una proprietà src

Poiché la variabile "hook" ha l'ambito per essere visibile nel codice falso in SpyOn e anche successivamente dopo che viene chiamato "reportABCEvent"

describe("Alphabetic.ads", function() {
    it("ABC events create an image request", function() {
    var hook={};
    spyOn(window, 'Image').andCallFake( function(x,y) {
          hook={ src: {} }
          return hook;
      }
      );
      reportABCEvent('testa', 'testb', 'testc');
      expect(hook.src).
      toEqual('[zubzub]&arg1=testa&arg2=testb&event_value=testc');
    });

Questo è per jasmine 1.3 ma potrebbe funzionare su 2.0 se "andCallFake" viene modificato nel nome 2.0


1

Sto usando una griglia di kendo e quindi non posso cambiare l'implementazione in un metodo getter, ma voglio testare questo (deridendo la griglia) e non testare la griglia stessa. Stavo usando un oggetto spia ma questo non supporta la derisione delle proprietà, quindi lo faccio:

    this.$scope.ticketsGrid = { 
        showColumn: jasmine.createSpy('showColumn'),
        hideColumn: jasmine.createSpy('hideColumn'),
        select: jasmine.createSpy('select'),
        dataItem: jasmine.createSpy('dataItem'),
        _data: []
    } 

È un po 'prolisso ma funziona a meraviglia


0

Sono un po 'in ritardo per la festa qui lo so ma,

Puoi accedere direttamente all'oggetto chiamate, che può darti le variabili per ogni chiamata

expect(spy.calls.argsFor(0)[0].value).toBe(expectedValue)

-3

Non puoi simulare la variabile ma puoi creare una funzione getter per essa e deridere quel metodo nel tuo file delle specifiche.

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.