web-dev-qa-db-fra.com

Jasmine JavaScript Testing - toBe vs toEqual

Disons que j'ai les éléments suivants:

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

Les deux tests ci-dessus vont réussir. Existe-t-il une différence entre toBe() et toEqual() lorsqu'il s'agit d'évaluer des nombres? Si oui, quand devrais-je utiliser l'un et pas l'autre?

305
Lloyd Banks

Pour les types primitifs (nombres, booléens, chaînes, etc.), il n'y a pas de différence entre toBe et toEqual; soit on travaillera pour 5, true ou "the cake is a lie".

Pour comprendre la différence entre toBe et toEqual, imaginons trois objets.

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

En utilisant une comparaison stricte (===), certaines choses sont "identiques":

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

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

> c.foo === b.foo
true

Mais certaines choses, même si elles sont "égales", ne sont pas "identiques", car elles représentent des objets qui vivent dans des emplacements différents en mémoire.

> b === c
false

Le matcher toBe de Jasmine n'est rien de plus qu'une enveloppe pour une comparaison d'égalité stricte

expect(a.foo).toBe(b.foo)

est la même chose que

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

Ne vous contentez pas de prendre ma parole pour cela; voir le code source de toBe .

Mais b et c représentent des objets fonctionnellement équivalents; ils ressemblent tous les deux

{ foo: { bar: 'baz' } }

Ne serait-il pas formidable de dire que b et c sont "égaux" même s'ils ne représentent pas le même objet?

Entrez toEqual, qui vérifie "l’égalité profonde" (c’est-à-dire effectue une recherche récursive dans les objets pour déterminer si les valeurs de leurs clés sont équivalentes). Les deux tests suivants réussiront:

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

J'espère que cela aide à clarifier certaines choses.

434
elreimundo

toBe() versus toEqual(): toEqual() vérifie l'équivalence. toBe(), d'autre part, s'assure qu'ils sont exactement le même objet.

Je dirais que vous utilisez toBe() lorsque vous comparez des valeurs et toEqual() lorsque vous comparez des objets.

Lors de la comparaison de types primitifs, toEqual() et toBe() donneront le même résultat. Lors de la comparaison d'objets, toBe() est une comparaison plus stricte. Si ce n'est pas exactement le même objet en mémoire, la valeur renvoyée est false. Donc, à moins que vous ne souhaitiez vous assurer qu'il s'agit exactement du même objet en mémoire, utilisez toEqual() pour comparer les objets.

Vérifiez ce lien pour plus d’informations: http://evanhahn.com/how-do-i-jasmine/

Maintenant, lorsque vous regardez la différence entre toBe() et toEqual() en ce qui concerne les chiffres, il ne devrait y avoir aucune différence tant que votre comparaison est correcte. 5 sera toujours équivalent à 5.

Un bel endroit pour jouer avec cela pour voir différents résultats est ici

Mettre à jour

Un moyen facile de regarder toBe() et toEqual() consiste à comprendre ce qu’ils font exactement en JavaScript. Selon l’API Jasmine, trouvé ici :

toEqual () fonctionne pour les littéraux simples et les variables, et devrait fonctionner pour les objets

toBe () compare avec ===

toEqual() et toBe() sont des opérateurs Javascripts === similaires, à l'exception de toBe() vérifie également qu'il s'agit bien du même objet, comme dans l'exemple ci-dessous objectOne === objectTwo //returns false. Cependant, toEqual() retournera true dans cette situation.

Maintenant, vous pouvez au moins comprendre pourquoi quand on vous en donne:

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

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

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

En effet, comme indiqué dans , cette réponse à une question différente mais similaire, , l'opérateur === signifie en réalité que les deux opérandes font référence au même objet ou, dans le cas de types de valeur, la même valeur.

75
Adjit

Pour citer le projet jasmine github,

expect(x).toEqual(y); compare les objets ou les primitives x et y et les transmet si elles sont équivalentes

expect(x).toBe(y); compare les objets ou les primitives x et y et passe s'ils sont le même objet

27
Tharaka

Regarder le code source de Jasmine apporte plus de lumière sur la question.

toBe est très simple et utilise simplement l'opérateur identité/égalité stricte, ===:

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

toEqual, par contre, a une longueur de près de 150 lignes et une gestion spéciale pour les objets intégrés tels que String, Number, Boolean, Date, Error, Element et RegExp. Pour les autres objets, il compare récursivement les propriétés.

Ceci est très différent du comportement de l'opérateur d'égalité, ==. Par exemple:

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
13
Tamlyn

toEqual() compare les valeurs si Primitive ou le contenu si Objets. toBe() compare les références.

Les codes/suites suivants doivent être explicites:

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
BeingSuman

Je pensais que quelqu'un aimerait une explication par exemple (annoté):

Ci-dessous, si ma fonction deepClone () remplit correctement sa fonction, le test (décrit dans l'appel 'it ()') réussira:

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

Bien sûr, ceci n’est pas une suite de tests complète pour mon deepClone (), car je n’ai pas vérifié ici si le littéral objet du tableau (et celui qui y est imbriqué) ont également une identité distincte, mais les mêmes valeurs.

1
Jared Tomaszewski