run - Jasmine JavaScript Testing-toBe vs toEqual
karma js (7)
Digamos que tengo lo siguiente:
var myNumber = 5;
expect(myNumber).toBe(5);
expect(myNumber).toEqual(5);
Ambas de las pruebas anteriores pasarán. ¿Hay una diferencia entre toBe()
y toEqual()
cuando se trata de evaluar números? Si es así, ¿cuándo debo usar uno y no el otro?
Mirar el código fuente de Jasmine arroja más luz sobre el tema.
toBe
es muy simple y solo usa el operador de igualdad de identidad / estricta, ===
:
function(actual, expected) {
return {
pass: actual === expected
};
}
toEqual
, por otro lado, tiene casi 150 líneas de largo y tiene un manejo especial para los objetos integrados como String
, Number
, Boolean
, Date
, Error
, Element
y RegExp
. Para otros objetos compara propiedades recursivamente.
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
Para citar el proyecto github jazmín,
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
Para los tipos primitivos (por ejemplo, números, booleanos, cadenas, etc.), no hay diferencia entre toBe
y toEqual
; cualquiera de los dos funcionará para 5
, true
, o "the cake is a lie"
.
Para entender la diferencia entre toBe
y 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 sean "iguales", no son "iguales", ya que representan objetos que viven en diferentes ubicaciones en la memoria.
> b === c
false
Jasmine''s toBe
matcher no es más que un envoltorio para una comparación de igualdad estricta
expect(a.foo).toBe(b.foo)
es lo mismo que
expect(a.foo === b.foo).toBe(true)
No solo tome mi palabra por ello; ver el código fuente para toBe .
Pero c
representan objetos funcionalmente equivalentes; ambos se ven como
{ foo: { bar: ''baz'' } }
¿No sería estupendo si pudiéramos decir que c
son "iguales" incluso si no representan el mismo objeto?
Ingrese 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). Las dos siguientes pruebas pasarán:
expect(b).not.toBe(c);
expect(b).toEqual(c);
Espero que ayude a aclarar algunas cosas.
Pensé que a alguien le podría gustar una explicación mediante (anotado) ejemplo:
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, esto no es un conjunto de prueba completo para mi deepClone (), ya que no he probado aquí si el objeto literal en la matriz (y el que está anidado en él) también tiene una identidad distinta pero los mismos valores.
Puntos a tener en cuenta:
-
toBe()
trata las comparaciones como lo haceObject.is()
. -
toEqual()
trata las comparaciones como hace===
.
Es por eso que para los tipos primitivos, toBe
y toEqual
no tienen mucha diferencia al probar la igualdad, pero para los tipos de referencia como los objetos, prefiere usar toEqual
para probar la igualdad.
toBe()
contra toEqual()
: toEqual()
verifica la equivalencia. toBe()
, por otro lado, se asegura de que sean exactamente el mismo objeto.
Yo diría que use toBe()
cuando compare valores, y toEqual()
cuando compare objetos.
Al comparar tipos primitivos, toEqual()
y toBe()
darán 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, use 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. 5
siempre será equivalente a 5
.
Un buen lugar para jugar con esto para ver diferentes resultados está here
Actualizar
Una forma fácil de ver toBe()
y toEqual()
es entender qué hacen exactamente en JavaScript. Según la API de Jasmine, encontrada here :
toEqual () funciona para literales y variables simples, y debería funcionar para objetos
toBe () se compara con
===
Esencialmente, lo que está diciendo es que toEqual()
y toBe()
son Javascripts ===
operador similares, excepto que toBe()
también está comprobando que sea exactamente el mismo objeto, como en el ejemplo siguiente objectOne === objectTwo //returns false
también. Sin embargo, toEqual()
devolverá verdadero en esa situación.
Ahora, al menos puedes entender por qué cuando se administra:
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 ===
realidad significa que ambos operandos hacen referencia al mismo objeto, o en el caso de los tipos de valor, tienen el mismo valor.
toEqual()
compara valores si Primitivo o contenido si Objetos. toBe()
compara referencias.
El siguiente código / suite debe ser auto explicativo:
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);
});
});