Test JavaScript Jasmine - toBe vs toEqual


348

Diciamo che ho il seguente:

var myNumber = 5;
expect(myNumber).toBe(5);
expect(myNumber).toEqual(5);

Entrambi i test di cui sopra passeranno. C'è una differenza tra toBe()e toEqual()quando si tratta di valutare i numeri? In tal caso, quando dovrei usare l'uno e non l'altro?


in poche parole: nessuna differenza tra i due quando si confrontano i primitivi; per gli oggetti -> toEqual()verrà confrontato per contenuto chiave / valori; toBe()confronta per riferimento oggetto.
Andre Elrico,

Risposte:


488

Per i tipi primitivi (ad esempio numeri, valori booleani, stringhe, ecc.), Non vi è alcuna differenza tra toBee toEqual; uno dei due lavorerà per 5, trueo "the cake is a lie".

Per capire la differenza tra toBee toEqual, immaginiamo tre oggetti.

var a = { bar: 'baz' },
    b = { foo: a },
    c = { foo: a };

Usando un confronto rigoroso ( ===), alcune cose sono "uguali":

> b.foo.bar === c.foo.bar
true

> b.foo.bar === a.bar
true

> c.foo === b.foo
true

Ma alcune cose, sebbene siano "uguali", non sono "uguali", poiché rappresentano oggetti che vivono in luoghi diversi nella memoria.

> b === c
false

Il toBematcher di Jasmine non è altro che un involucro per un rigoroso confronto sull'uguaglianza

expect(c.foo).toBe(b.foo)

è la stessa cosa di

expect(c.foo === b.foo).toBe(true)

Non limitarti a crederci sulla parola; vedere il codice sorgente per toBe .

Ma be crappresentano oggetti funzionalmente equivalenti; sembrano entrambi

{ foo: { bar: 'baz' } }

Non sarebbe bello se potessimo dirlo be csiano "uguali" anche se non rappresentano lo stesso oggetto?

Invio toEqual, che verifica "uguaglianza profonda" (ovvero effettua una ricerca ricorsiva attraverso gli oggetti per determinare se i valori delle loro chiavi sono equivalenti). Passeranno entrambi i seguenti test:

expect(b).not.toBe(c);
expect(b).toEqual(c);

Spero che questo aiuti a chiarire alcune cose.


17
"Per i tipi primitivi (ad esempio numeri, valori booleani, stringhe, ecc.), Non vi è alcuna differenza tra toBe e toEqual" - poiché risulta che ciò non è del tutto vero. expect(0).toBe(-0)passerà ma expect(0).toEqual(-0)fallirà.
mgol

11
tl; dr - toBeusa l'uguaglianza rigorosa - confronta per riferimento, toEqualusa l'equivalenza della proprietà. Consigliato da usare toEqualper i primitivi
Drenai il

1
Quindi quale dovremmo usare per i primitivi e perché? Drenai, perché mi consiglia di Equal?
Patrick Szalapski

@PatrickSzalapski Posso solo immaginare il ragionamento di Denai, ma toEqualè molto più attenti di uguaglianza ( 0 != -0, "hi" = new String("hi"), ecc), quindi mi consiglia di utilizzare toEqual esclusivamente a meno che non si sta effettivamente preoccupati per l'equivalenza di riferimento. Vedi tutti i controlli toEqualeffettuati nel eqmetodo qui: github.com/jasmine/jasmine/blob/master/src/core/matchers/…
River

Penso che sia meglio usare ToBe quando si confrontano le primitive per salvare il sovraccarico che si fa in Equal.
GarfieldKlon,

81

toBe()contro toEqual(): toEqual()controlla l'equivalenza. toBe(), d'altra parte, si assicura che siano esattamente lo stesso oggetto.

Direi uso toBe()quando si confrontano i valori e toEqual()quando si confrontano gli oggetti.

Quando si confrontano i tipi primitivi toEqual()e si toBe()otterrà lo stesso risultato. Quando si confrontano oggetti, toBe()è un confronto più rigoroso e se non è lo stesso oggetto in memoria, questo restituirà false. Quindi, a meno che non si voglia assicurarsi che sia esattamente lo stesso oggetto in memoria, utilizzare toEqual()per confrontare gli oggetti.

Dai un'occhiata a questo link per maggiori informazioni: http://evanhahn.com/how-do-i-jasmine/

Ora, quando si guarda la differenza tra toBe()e toEqual()quando si tratta di numeri, non ci dovrebbero essere differenze finché il confronto è corretto. 5sarà sempre equivalente a 5.

Un bel posto per giocare con questo per vedere diversi risultati è qui

Aggiornare

Un modo semplice per vedere toBe()ed toEqual()è capire cosa fanno esattamente in JavaScript. Secondo l'API Jasmine, si trova qui :

toEqual () funziona per semplici letterali e variabili e dovrebbe funzionare per gli oggetti

toBe () si confronta con ===

In sostanza, ciò che sta dicendo è toEqual()e toBe()sono ===operatori Javascripts simili , tranne che toBe()sta anche verificando che si tratti esattamente dello stesso oggetto, anche in questo esempio objectOne === objectTwo //returns false. Tuttavia, toEqual()tornerà vero in quella situazione.

Ora, almeno puoi capire perché quando ti viene dato:

var objectOne = {
    propertyOne: str,
    propertyTwo: num    
}

var objectTwo = {
    propertyOne: str,
    propertyTwo: num    
}

expect(objectOne).toBe(objectTwo); //returns false

Questo perché, come indicato in questa risposta a una domanda diversa, ma simile, l' ===operatore in realtà significa che entrambi gli operandi fanno riferimento allo stesso oggetto o, nel caso di tipi di valore, hanno lo stesso valore.


4
Questo evita di rispondere alla domanda. Spieghi cosa toEqual()significa dicendo che toEqual()controlla l'equivalenza , ma l'ovvia domanda successiva va bene, quindi cosa significa "equivalente"? Una descrizione dell'algoritmo utilizzato per determinare "equivalenza", o almeno esempi di casi in cui il comportamento toEqual()e le toBe()differenze, renderebbe questo più utile.
Mark Amery,

8
Non solo questo non risponde alla domanda, ma è sbagliato . toEqualdovrebbe essere usato per un confronto profondo tra oggetti, no toBe. jsfiddle.net/bBL9P/67
Lloyd Banks,

3
Sembra che le persone non si preoccupino di verificare se ciò che stanno dicendo è corretto. Sia ToBe che ToEqual sembrano essere confronti severi. Provalo ... Quindi nei miei test non ho ancora trovato la differenza. per esempio: var f = 1; var g = "1" prevedono (f == g) .toEqual (true); // true prevede (f) .toEqual (g); // false prevede (f) .toBe (g); // false
user1809104

6
Questo è completamente sbagliato. nontoEqual è affatto lo stesso di ==.
meagar

6
Leggi i commenti sopra. expect(1).toEqual('1')fallisce, mentre 1 == '1'è vero. toEqualnon ha niente a che fare con ==. È come ===tranne che confronterà gli oggetti in un modo simile al confronto per valore.
meagar

33

Per citare il progetto github al gelsomino,

expect(x).toEqual(y); confronta gli oggetti o le primitive xey e passa se sono equivalenti

expect(x).toBe(y);confronta oggetti o primitive xey e passa se sono lo stesso oggetto


14

Guardando il codice sorgente di Jasmine si fa più luce sulla questione.

toBeè molto semplice e utilizza solo l'operatore identità / rigorosa parità ===:

  function(actual, expected) {
    return {
      pass: actual === expected
    };
  }

toEqual, D'altra parte, è lungo circa 150 linee ed ha una gestione speciale per costruito in oggetti come String, Number, Boolean, Date, Error, Elemente RegExp. Per altri oggetti confronta ricorsivamente le proprietà.

Questo è molto diverso dal comportamento dell'operatore uguaglianza, ==. Per esempio:

var simpleObject = {foo: 'bar'};
expect(simpleObject).toEqual({foo: 'bar'}); //true
simpleObject == {foo: 'bar'}; //false

var castableObject = {toString: function(){return 'bar'}};
expect(castableObject).toEqual('bar'); //false
castableObject == 'bar'; //true

2

toEqual()confronta i valori se Primitivo o il contenuto se Oggetti. toBe()confronta i riferimenti.

Il seguente codice / suite dovrebbe essere autoesplicativo:

describe('Understanding toBe vs toEqual', () => {
  let obj1, obj2, obj3;

  beforeEach(() => {
    obj1 = {
      a: 1,
      b: 'some string',
      c: true
    };

    obj2 = {
      a: 1,
      b: 'some string',
      c: true
    };

    obj3 = obj1;
  });

  afterEach(() => {
    obj1 = null;
    obj2 = null;
    obj3 = null;
  });

  it('Obj1 === Obj2', () => {
    expect(obj1).toEqual(obj2);
  });

  it('Obj1 === Obj3', () => {
    expect(obj1).toEqual(obj3);
  });

  it('Obj1 !=> Obj2', () => {
    expect(obj1).not.toBe(obj2);
  });

  it('Obj1 ==> Obj3', () => {
    expect(obj1).toBe(obj3);
  });
});

1

Pensavo che qualcuno potesse gradire la spiegazione con un esempio (annotato):

Di seguito, se la mia funzione deepClone () fa bene il suo lavoro, il test (come descritto nella chiamata 'it ()') avrà esito positivo:

describe('deepClone() array copy', ()=>{
    let source:any = {}
    let clone:any = source
    beforeAll(()=>{
        source.a = [1,'string literal',{x:10, obj:{y:4}}]
        clone = Utils.deepClone(source) // THE CLONING ACT TO BE TESTED - lets see it it does it right.
    })
    it('should create a clone which has unique identity, but equal values as the source object',()=>{
        expect(source !== clone).toBe(true) // If we have different object instances...
        expect(source).not.toBe(clone) // <= synonymous to the above. Will fail if: you remove the '.not', and if: the two being compared are indeed different objects.
        expect(source).toEqual(clone) // ...that hold same values, all tests will succeed.
    })
})

Naturalmente questa non è una suite di test completa per il mio deepClone (), poiché non ho testato qui se l'oggetto letterale nell'array (e quello nidificato in esso) hanno anche identità distinta ma stessi valori.


0

Penso che ToEqual stia verificando un uguale uguale, toBe è lo stesso riferimento di 2 variabili

  it('test me', () => {
    expect([] === []).toEqual(false) // true
    expect([] == []).toEqual(false) // true

    expect([]).toEqual([]); // true // deep check
    expect([]).toBe([]); // false
  })

-2

Punti da notare:

  • toBe()tratta i confronti come Object.is()fa.
  • toEqual()tratta i confronti come ===fa.

Ecco perché per i tipi primitivi toBee toEqualnon hanno molta differenza quando si esegue il test per l'uguaglianza, ma per i tipi di riferimento come gli oggetti, si preferisce utilizzare toEqualper verificare l'uguaglianza.

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.