Jasmine JavaScript Testing - toBe vs toEqual

348

Angenommen, ich habe Folgendes:

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

Beide oben genannten Tests bestehen. Gibt es einen Unterschied zwischen toBe()und toEqual()bei der Bewertung von Zahlen? Wenn ja, wann sollte ich das eine und nicht das andere verwenden?

Lloyd Banks
quelle
auf den Punkt gebracht: kein Unterschied zwischen den beiden beim Vergleich von Primitiven; für Objekte -> toEqual()wird nach Schlüssel / Wert-Inhalt verglichen; toBe()wird anhand der Objektreferenz verglichen.
Andre Elrico

Antworten:

488

Für primitive Typen (z. B. Zahlen, Boolesche Werte, Zeichenfolgen usw.) gibt es keinen Unterschied zwischen toBeund toEqual; entweder arbeiten für 5, trueoder "the cake is a lie".

Um den Unterschied zwischen toBeund zu verstehen toEqual, stellen wir uns drei Objekte vor.

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

Bei einem strengen Vergleich ( ===) sind einige Dinge "gleich":

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

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

> c.foo === b.foo
true

Aber einige Dinge sind, obwohl sie "gleich" sind, nicht "gleich", da sie Objekte darstellen, die an verschiedenen Orten im Gedächtnis leben.

> b === c
false

Jasmines toBeMatcher ist nichts anderes als ein Wrapper für einen strengen Gleichheitsvergleich

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

ist das gleiche wie

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

Nimm nicht einfach mein Wort dafür; Siehe den Quellcode für toBe .

Aber bund crepräsentieren funktional äquivalente Objekte; sie sehen beide so aus

{ foo: { bar: 'baz' } }

Wäre es nicht großartig, wenn wir das sagen könnten bund c"gleich" sind, auch wenn sie nicht dasselbe Objekt darstellen?

Geben Sie ein toEqual, wodurch "tiefe Gleichheit" überprüft wird (dh eine rekursive Suche durch die Objekte durchgeführt wird, um festzustellen, ob die Werte für ihre Schlüssel äquivalent sind). Beide folgenden Tests bestehen:

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

Hoffe, das hilft, einige Dinge zu klären.

elreimundo
quelle
17
"Für primitive Typen (z. B. Zahlen, Boolesche Werte, Zeichenfolgen usw.) gibt es keinen Unterschied zwischen toBe und toEqual" - wie sich herausstellt, ist dies nicht ganz richtig. expect(0).toBe(-0)wird bestehen, aber expect(0).toEqual(-0)scheitern.
mgol
11
tl; dr - toBeverwendet strikte Gleichheit - vergleicht anhand von Referenzen, toEqualverwendet Eigenschaftsäquivalenz. Empfohlen toEqualfür Primitive
Drenai
1
Welches sollten wir also für Primitive verwenden und warum? Drenai, warum empfehlen Sie toEqual?
Patrick Szalapski
@PatrickSzalapski Ich kann nur an Denai Argumentation erraten, aber toEqualist viel vorsichtiger über Gleichheit ( 0 != -0, "hi" = new String("hi")usw.), so dass ich mit empfehlen würde toEqual ausschließlich es sei denn , Sie sind besorgt tatsächlich über Referenz Gleichwertigkeit. Alle Überprüfungen toEqualder eqMethode finden Sie hier: github.com/jasmine/jasmine/blob/master/src/core/matchers/…
River
Ich denke, es ist besser, toBe zu verwenden, wenn Primitive verglichen werden, um den Overhead zu sparen, der in toEqual gemacht wird.
GarfieldKlon
81

toBe()versus toEqual(): toEqual()prüft die Äquivalenz. toBe()stellt andererseits sicher, dass es sich um genau dasselbe Objekt handelt.

Ich würde sagen, verwenden Sie toBe()beim Vergleichen von Werten und toEqual()beim Vergleichen von Objekten.

Beim Vergleich von primitiven Typen, toEqual()und toBe()das gleiche Ergebnis ergibt. Beim Vergleichen von Objekten toBe()handelt es sich um einen strengeren Vergleich. Wenn es sich nicht um genau dasselbe Objekt im Speicher handelt, wird false zurückgegeben. Wenn Sie also nicht sicherstellen möchten, dass es sich um genau dasselbe Objekt im Speicher handelt, verwenden Sie es toEqual()zum Vergleichen von Objekten.

Weitere Informationen finden Sie unter diesem Link: http://evanhahn.com/how-do-i-jasmine/

Wenn Sie nun den Unterschied zwischen toBe()und toEqual()in Bezug auf Zahlen betrachten, sollte es keinen Unterschied geben, solange Ihr Vergleich korrekt ist. 5wird immer gleich sein 5.

Ein schöner Ort, um damit herumzuspielen und verschiedene Ergebnisse zu sehen, ist hier

Aktualisieren

Eine einfache Möglichkeit zu betrachten toBe()und toEqual()zu verstehen ist, was genau sie in JavaScript tun. Laut Jasmine API hier zu finden :

toEqual () funktioniert für einfache Literale und Variablen und sollte für Objekte funktionieren

toBe () vergleicht mit ===

Im Wesentlichen , was das sagt , ist , toEqual()und toBe()sind ähnlich Javascripts ===Betreiber außer toBe()auch sicherstellen, ist die Überprüfung ist es genau das gleiche Objekt, dass für das Beispiel unten objectOne === objectTwo //returns falseals auch. In toEqual()dieser Situation wird jedoch true zurückgegeben.

Jetzt können Sie zumindest verstehen, warum, wenn gegeben:

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

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

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

Dies liegt daran, ===dass der Operator , wie in dieser Antwort auf eine andere, aber ähnliche Frage angegeben, tatsächlich bedeutet, dass beide Operanden auf dasselbe Objekt verweisen oder bei Werttypen denselben Wert haben.

Adjit
quelle
4
Dies vermeidet die Beantwortung der Frage. Sie erklären, was toEqual()bedeutet, indem Sie sagen, dass die toEqual()Äquivalenz überprüft wird , aber die naheliegende nächste Frage ist in Ordnung. Was bedeutet also "Äquivalent"? Eine Beschreibung des Algorithmus zur Bestimmung der "Äquivalenz" oder zumindest Beispiele für Fälle, in denen sich das Verhalten von toEqual()und das Verhalten toBe()unterscheiden, würde dies nützlicher machen.
Mark Amery
8
Dies beantwortet nicht nur nicht die Frage, sondern ist auch falsch . toEqualsollte für einen tiefen Vergleich zwischen Objekten verwendet werden, nicht toBe. jsfiddle.net/bBL9P/67
Lloyd Banks
3
Es scheint, dass sich die Leute nicht die Mühe machen zu testen, ob das, was sie sagen, richtig ist. Sowohl toBe als auch toEqual scheinen strenge Vergleiche zu sein. Teste es ... Also in meinen Tests bin ich noch nicht in der Lage, einen Unterschied zu finden. zum Beispiel: var f = 1; var g = "1" erwarten (f == g) .toEqual (true); // true erwarten (f) .toEqual (g); // false erwarten (f) .toBe (g); // false
user1809104
6
Das ist völlig falsch. toEqualist überhaupt nicht das gleiche wie ==.
Meagar
6
Lesen Sie die Kommentare oben. expect(1).toEqual('1')schlägt fehl, solange 1 == '1'es wahr ist. toEqualhat nichts damit zu tun ==. Es ist so ===, als würde es Objekte auf ähnliche Weise wie beim Vergleich nach Werten vergleichen.
Meagar
33

Um das Jasmin-Github-Projekt zu zitieren:

expect(x).toEqual(y); vergleicht Objekte oder Grundelemente x und y und übergibt, wenn sie äquivalent sind

expect(x).toBe(y);vergleicht Objekte oder Grundelemente x und y und übergibt, wenn sie dasselbe Objekt sind

Tharaka
quelle
14

Ein Blick auf den Jasmine-Quellcode wirft mehr Licht auf das Problem.

toBeist sehr einfach und verwendet nur den Identitäts- / strengen Gleichheitsoperator ===:

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

toEqual, Auf der anderen Seite, ist fast 150 Zeilen lang und hat eine spezielle Behandlung in Objekten wie gebaut für String, Number, Boolean, Date, Error, Elementund RegExp. Für andere Objekte werden Eigenschaften rekursiv verglichen.

Dies unterscheidet sich stark vom Verhalten des Gleichheitsoperators ==. Zum Beispiel:

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
Tamlyn
quelle
2

toEqual()vergleicht Werte, wenn primitiv, oder Inhalt, wenn Objekte. toBe()vergleicht Referenzen.

Der folgende Code / die folgende Suite sollte selbsterklärend sein:

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);
  });
});
Mensch sein
quelle
1

Dachte, jemand könnte eine Erklärung anhand eines (kommentierten) Beispiels mögen:

Wenn meine deepClone () -Funktion ihre Aufgabe richtig erledigt, ist der Test (wie im Aufruf 'it ()' beschrieben) erfolgreich:

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

Dies ist natürlich keine vollständige Testsuite für mein deepClone (), da ich hier nicht getestet habe, ob das Objektliteral im Array (und das darin verschachtelte) ebenfalls eine eindeutige Identität, aber dieselben Werte aufweist.

Jared Tomaszewski
quelle
0

Ich denke, toEqual prüft tief gleich, toBe ist die gleiche Referenz von 2 Variablen

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

    expect([]).toEqual([]); // true // deep check
    expect([]).toBe([]); // false
  })
feyzullah yıldız
quelle
-2

Zu beachtende Punkte:

  • toBe()behandelt Vergleiche wie Object.is().
  • toEqual()behandelt Vergleiche wie ===.

Aus diesem Grunde für primitive Typen, toBeund toEqualhaben nicht viel Unterschied , wenn für die Gleichstellung Prüfung, sondern auch für Referenztypen wie Objekte, die Sie lieber verwenden toEqualfür Gleichheit zu testen.

John Mutuma
quelle