Jasmine JavaScript-testning - toBe vs toEqual


Låt oss säga att jag har följande:

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

Båda testerna ovan kommer att gå igenom. Finns det en skillnad mellan toBe() och toEqual() när det gäller att utvärdera siffror? Om så är fallet, när bör jag använda det ena och inte det andra?

Svar #1

För primitiva typer (t.ex. nummer, booleaner, strängar, etc.), finns det ingen skillnad mellan toBe och toEqual; vilken som helst fungerar för 5, true eller "the cake is a lie".

För att förstå skillnaden mellan toBe och toEqual, låt oss föreställa oss tre objekt.

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

Med en strikt jämförelse (===) är vissa saker "samma":

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

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

> c.foo === b.foo
true

Men vissa saker, även om de är "lika", är inte "samma", eftersom de representerar objekt som finns på olika platser i minnet.

> b === c
false

Jasmines toBe-matcher är inget annat än ett omslag för en strikt jämförelse av likhet

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

är samma sak som

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

Ta inte bara mitt ord för det; se källkoden för toBe.

Men b och c representerar funktionellt ekvivalenta objekt; de ser båda ut som

{ foo: { bar: 'baz' } }

Skulle det inte vara fantastiskt om vi kunde säga att b och c är "lika" även om de inte representerar samma objekt?

Ange toEqual, som kontrollerar "djup jämställdhet" (dvs. gör en rekursiv sökning genom objekten för att avgöra om värdena för deras nycklar är ekvivalenta). Båda följande tester kommer att lyckas:

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

Svar #2

toBe() kontra toEqual(): toEqual() kontrollerar likvärdighet. toBe(), å andra sidan, försäkrar sig om att de är exakt samma objekt.

Jag skulle säga att använda toBe() när du jämför värden, och toEqual() när du jämför objekt.

När man jämför primitiva typer kommer toEqual() och toBe() att ge samma resultat. När man jämför objekt är toBe() en striktare jämförelse, och om det inte är exakt samma objekt i minnet kommer detta att returnera false. Så om du inte vill säkerställa att det är exakt samma objekt i minnet, använd toEqual() för att jämföra objekt.

Kolla in den här länken för mer information: http://evanhahn.com/how-do-i-jasmine/

Nu när man tittar på skillnaden mellan toBe() och toEqual() när det gäller siffror, bör det inte finnas någon skillnad så länge din jämförelse är korrekt. 5 kommer alltid att vara lika med 5.

En trevlig plats att leka med detta för att se olika resultat är här

Uppdatering

Ett enkelt sätt att se på toBe() och toEqual() är att förstå vad de exakt gör i JavaScript. Enligt Jasmine API, som finns här:

toEqual() fungerar för enkla litteraler och variabler, och bör fungera för objekt

toBe() jämför med ===

I huvudsak säger det att toEqual() och toBe() är liknande Javascripts ===-operator, förutom att toBe() också kontrollerar att det är exakt samma objekt, vilket innebär att i exemplet nedan objectOne === objectTwo/returns false. Däremot kommer toEqual() att returnera true i den situationen.

Nu kan du åtminstone förstå varför när det ges:

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

var objectTwo = {
    propertyOne: str,
    propertyTwo: num    
}
expect(objectOne).toBe(objectTwo); //returns false

Det beror på att, som anges i detta svar på en annan, men liknande fråga, betyder ===-operatorn faktiskt att båda operanderna refererar till samma objekt, eller i fallet med värdetyper, har samma värde.

Svar #3

För att citera jasmine GitHub-projektet,

expect(x).toEqual(y); jämför objekt eller primitiva värden x och y och godkänns om de är lika

expect(x).toBe(y); jämför objekt eller primitiva x och y och går igenom om de är samma objekt

Svar #4

Att titta på Jasmine-källkoden ger mer klarhet i problemet.

toBe är mycket enkelt och använder bara identitets-/strikt jämförelseoperatorn, ===:

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

toEqual, å andra sidan, är nästan 150 rader lång och har speciell hantering för inbyggda objekt som String, Number, Boolean, Date, Error, Element och RegExp. För andra objekt jämför den egenskaper rekursivt.

Detta är mycket annorlunda än beteendet hos likhetsoperatorn, ==. Till exempel:

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

Relaterade artiklar