Prueba de jazmín JavaScript - toBe vs toEqual

348

Digamos que tengo lo siguiente:

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

Ambas pruebas anteriores pasarán. ¿Hay alguna diferencia entre toBe()y toEqual()cuando se trata de evaluar números? Si es así, ¿cuándo debo usar uno y no el otro?

Lloyd Banks
fuente
en pocas palabras: no hay diferencia entre los dos cuando se comparan primitivas; para objetos -> toEqual()se comparará por clave / valores-contenido; toBe()se comparará por referencia de objeto.
Andre Elrico

Respuestas:

488

Para los tipos primitivos (por ejemplo, números, booleanos, cadenas, etc.), no hay diferencia entre toBey toEqual; o bien se trabajará para 5, trueo "the cake is a lie".

Para entender la diferencia entre toBey toEqual, imaginemos tres objetos.

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

Usando una comparación estricta ( ===), algunas cosas son "iguales":

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

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

> c.foo === b.foo
true

Pero algunas cosas, aunque son "iguales", no son "lo mismo", ya que representan objetos que viven en diferentes lugares en la memoria.

> b === c
false

El toBecomparador de Jasmine no es más que un envoltorio para una estricta comparación de igualdad

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

es lo mismo que

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

No solo confíes en mi palabra; vea el código fuente de toBe .

Pero by crepresentan objetos funcionalmente equivalentes; ambos se ven como

{ foo: { bar: 'baz' } }

¿No sería genial si pudiéramos decir eso by cser "iguales" incluso si no representan el mismo objeto?

Enter toEqual, que verifica la "igualdad profunda" (es decir, realiza una búsqueda recursiva a través de los objetos para determinar si los valores de sus claves son equivalentes). Ambas pruebas pasarán:

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

Espero que ayude a aclarar algunas cosas.

elreimundo
fuente
17
"Para los tipos primitivos (por ejemplo, números, booleanos, cadenas, etc.), no hay diferencia entre toBe y toEqual", ya que resulta que esto no es del todo cierto. expect(0).toBe(-0)pasará pero expect(0).toEqual(-0)fallará.
mgol
11
tl; dr - toBeusa igualdad estricta - compara por referencia, toEqualusa equivalencia de propiedad. Recomendado para usar toEqualen primitivas
Drenai
1
Entonces, ¿cuál deberíamos usar para las primitivas y por qué? Drenai, ¿por qué me recomiendan a Equal?
Patrick Szalapski
@PatrickSzalapski Sólo puedo imaginar en el razonamiento de Denai, pero toEquales mucho más cuidado con la igualdad ( 0 != -0, "hi" = new String("hi"), etc.), así que me gustaría recomendar el uso toEqual en exclusiva a menos que estés realmente preocupados por la equivalencia de referencia. Vea todos los controles realizados toEqualen el eqmétodo aquí: github.com/jasmine/jasmine/blob/master/src/core/matchers/…
River
Creo que es mejor usar toBe al comparar primitivas para guardar la sobrecarga que se hace en toEqual.
GarfieldKlon
81

toBe()versus toEqual(): toEqual()verifica la equivalencia. toBe(), por otro lado, se asegura de que sean exactamente el mismo objeto.

Yo diría usar toBe()cuando se comparan valores y toEqual()cuando se comparan objetos.

Al comparar tipos primitivos, toEqual()y toBe()dará el mismo resultado. Al comparar objetos, toBe()es una comparación más estricta, y si no es exactamente el mismo objeto en la memoria, esto devolverá falso. Entonces, a menos que desee asegurarse de que sea exactamente el mismo objeto en la memoria, utilícelo toEqual()para comparar objetos.

Consulte este enlace para obtener más información: http://evanhahn.com/how-do-i-jasmine/

Ahora, al observar la diferencia entre toBe()y toEqual()cuando se trata de números, no debería haber ninguna diferencia siempre que su comparación sea correcta. 5siempre será equivalente a 5.

Un buen lugar para jugar con esto para ver diferentes resultados está aquí

Actualizar

Una manera fácil de ver toBe()y toEqual()entender es qué hacen exactamente en JavaScript. Según la API de Jasmine, que se encuentra aquí :

toEqual () funciona para literales y variables simples, y debería funcionar para objetos

toBe () se compara con ===

Esencialmente, lo que está diciendo es toEqual()y toBe()es un ===operador Javascripts similar , excepto toBe()que también se está verificando para asegurarse de que sea exactamente el mismo objeto, en eso también para el ejemplo a continuación objectOne === objectTwo //returns false. Sin embargo, toEqual()volverá cierto en esa situación.

Ahora, al menos puede entender por qué cuando se le da:

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

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

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

Esto se debe a que, como se indica en esta respuesta a una pregunta diferente pero similar, el ===operador en realidad significa que ambos operandos hacen referencia al mismo objeto, o en el caso de tipos de valor, tienen el mismo valor.

Adjit
fuente
44
Esto evita responder la pregunta. Explica qué toEqual()hace al decir que toEqual()verifica la equivalencia , pero la siguiente pregunta obvia está bien, entonces, ¿qué significa "equivalente"? Una descripción del algoritmo utilizado para determinar la "equivalencia", o al menos ejemplos de casos en los que el comportamiento toEqual()y la toBe()diferencia, lo haría más útil.
Mark Amery el
8
Esto no solo no responde la pregunta, sino que está mal . toEqualdebe usarse para una comparación profunda entre objetos, no toBe. jsfiddle.net/bBL9P/67
Lloyd Banks
3
Parece que las personas no se molestan en probar si lo que dicen es correcto. Tanto toBe como toEqual parecen ser comparaciones estrictas. Pruébalo ... Así que en mi prueba aún no he encontrado una diferencia. por ejemplo: var f = 1; var g = "1" esperar (f == g) .toEqual (verdadero); // verdadero esperar (f) .toEqual (g); // falso esperar (f) .toBe (g); // falso
usuario1809104
66
Esto está completamente mal. notoEqual es lo mismo que ==.
Meagar
66
Lee los comentarios anteriores. expect(1).toEqual('1')falla, mientras que 1 == '1'es cierto. toEqualno tiene nada que ver con ==. Es como, ===excepto que comparará objetos de una manera similar a la comparación por valor.
Meagar
33

Para citar el proyecto jazmín github,

expect(x).toEqual(y); compara objetos o primitivas x e y y pasa si son equivalentes

expect(x).toBe(y);compara objetos o primitivas x e y y pasa si son el mismo objeto

Tharaka
fuente
14

Mirando el código fuente de Jasmine arroja más luz sobre el tema.

toBees muy simple y solo usa el operador de identidad / igualdad estricta ===:

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

toEqualPor otra parte, es casi 150 líneas de largo y tiene un manejo especial para la construcción de objetos como String, Number, Boolean, Date, Error, Elementy RegExp. Para otros objetos compara recursivamente propiedades.

Esto es muy diferente del comportamiento del operador de igualdad, ==. Por ejemplo:

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
fuente
2

toEqual()compara valores si es Primitivo o contenidos si es Objetos. toBe()compara referencias.

El siguiente código / suite debe explicarse por sí mismo:

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);
  });
});
Ser humano
fuente
1

Pensé que a alguien le gustaría una explicación con un ejemplo (anotado):

A continuación, si mi función deepClone () hace su trabajo correctamente, la prueba (como se describe en la llamada 'it ()' tendrá éxito:

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

Por supuesto, este no es un conjunto de pruebas completo para mi deepClone (), ya que no he probado aquí si el objeto literal en la matriz (y el anidado allí) también tiene una identidad distinta pero los mismos valores.

Jared Tomaszewski
fuente
0

Creo que toEqual está comprobando la igualdad profunda, toBe es la misma referencia de 2 variables

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

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

Puntos a tener en cuenta:

  • toBe()trata las comparaciones como lo Object.is()hace.
  • toEqual()trata las comparaciones como lo ===hace.

Es por eso que para los tipos primitivos, toBey toEqualno tienen mucha diferencia al probar la igualdad, pero para los tipos de referencia como los objetos, preferiría usar toEqualpara probar la igualdad.

John Mutuma
fuente