Jasmine JavaScript Testing - toBe vs toEqual

348

Digamos que tenho o seguinte:

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

Ambos os testes acima serão aprovados. Existe uma diferença entre toBe()e toEqual()quando se trata de avaliar números? Se sim, quando devo usar um e não o outro?

Lloyd Banks
fonte
em poucas palavras: não há diferença entre os dois ao comparar primitivos; para objetos -> toEqual()será comparado por conteúdo-chave / valores; toBe()irá comparar por referência de objeto.
Andre Elrico 20/01

Respostas:

488

Para tipos primitivos (por exemplo, números, booleanos, seqüências de caracteres, etc.), não há diferença entre toBee toEqual; qualquer um irá trabalhar para 5, trueou "the cake is a lie".

Para entender a diferença entre toBee toEqual, vamos imaginar três objetos.

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

Usando uma comparação estrita ( ===), algumas coisas são "iguais":

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

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

> c.foo === b.foo
true

Mas algumas coisas, mesmo sendo "iguais", não são "iguais", pois representam objetos que vivem em diferentes locais da memória.

> b === c
false

O toBepar de Jasmine não passa de um invólucro para uma comparação estrita de igualdade

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

é a mesma coisa que

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

Não basta aceitar minha palavra; veja o código fonte para toBe .

Mas be crepresentam objetos funcionalmente equivalentes; ambos se parecem

{ foo: { bar: 'baz' } }

Não seria ótimo se pudéssemos dizer isso be c"iguais", mesmo que não representem o mesmo objeto?

Enter toEqual, que verifica "profunda igualdade" (ou seja, faz uma pesquisa recursiva nos objetos para determinar se os valores para suas chaves são equivalentes). Os dois testes a seguir serão aprovados:

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

Espero que ajude a esclarecer algumas coisas.

elreimundo
fonte
17
"Para tipos primitivos (por exemplo, números, booleanos, strings, etc.), não há diferença entre toBe e toEqual" - como se vê, isso não é inteiramente verdade. expect(0).toBe(-0)vai passar, mas expect(0).toEqual(-0)vai falhar.
mgol 08/02
11
tl; dr - toBeusa igualdade estrita - compara por referência, toEqualusa equivalência de propriedade. Recomendado para uso toEqualem primitivos
Drenai
11
Então, qual deles devemos usar para primitivos e por quê? Drenai, por que você recomenda toEqual?
Patrick Szalapski 7/03/19
@PatrickSzalapski só posso adivinhar o raciocínio de Denai, mas toEqualé muito mais cuidadoso sobre a igualdade ( 0 != -0, "hi" = new String("hi"), etc.), então eu recomendo usar toEqual exclusivamente a menos que você está realmente preocupado com a equivalência de referência. Veja todas as verificações realizadas toEqualno eqmétodo aqui: github.com/jasmine/jasmine/blob/master/src/core/matchers/…
Rio
Eu acho que é melhor usar toBe ao comparar primitivas para economizar a sobrecarga que é feita no toEqual.
GarfieldKlon
81

toBe()versus toEqual(): toEqual()verifica a equivalência. toBe(), por outro lado, garante que eles sejam exatamente o mesmo objeto.

Eu diria que use toBe()ao comparar valores e toEqual()ao comparar objetos.

Ao comparar tipos primitivos, toEqual()e toBe()produzirá o mesmo resultado. Ao comparar objetos, toBe()é uma comparação mais rigorosa e, se não for exatamente o mesmo objeto na memória, isso retornará falso. Portanto, a menos que você queira ter certeza de que é exatamente o mesmo objeto na memória, use-o toEqual()para comparar objetos.

Confira este link para mais informações: http://evanhahn.com/how-do-i-jasmine/

Agora, ao analisar a diferença entre toBe()e toEqual()quando se trata de números, não deve haver nenhuma diferença, desde que sua comparação esteja correta. 5sempre será equivalente a 5.

Um bom lugar para brincar com isso e ver resultados diferentes é aqui

Atualizar

Uma maneira fácil de ver toBe()e toEqual()entender o que exatamente eles fazem em JavaScript. De acordo com a API do Jasmine, encontrada aqui :

toEqual () funciona para literais e variáveis ​​simples e deve funcionar para objetos

toBe () se compara com ===

Essencialmente, o que isso está dizendo é toEqual()e toBe()é um ===operador Javascripts semelhante , exceto que toBe()também está verificando se o objeto é exatamente o mesmo, no exemplo abaixo objectOne === objectTwo //returns falsetambém. No entanto, toEqual()retornará verdadeiro nessa situação.

Agora, você pode pelo menos entender o porquê quando determinado:

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

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

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

Isso ocorre porque, conforme declarado nesta resposta a uma pergunta diferente, mas semelhante, o ===operador realmente significa que ambos os operandos referenciam o mesmo objeto ou, no caso de tipos de valor, têm o mesmo valor.

Adjit
fonte
4
Isso evita responder à pergunta. Você explica o toEqual()que diz dizendo que toEqual()verifica a equivalência , mas a próxima pergunta óbvia é boa; então, o que significa "equivalente"? Uma descrição do algoritmo usado para determinar a "equivalência", ou pelo menos exemplos de casos em que o comportamento toEqual()e a toBe()diferença diferem, tornariam isso mais útil.
Mark Amery
8
Isso não apenas não responde à pergunta, mas está errado . toEqualdeve ser usado para comparação profunda entre objetos, não toBe. jsfiddle.net/bBL9P/67
Lloyd Banks
3
Parece que as pessoas não estão se preocupando em testar se o que estão dizendo está correto. Tanto toBe quanto toEqual parecem ser comparações estritas. Teste ... Então, no meu teste, ainda estou para encontrar a diferença. por exemplo: var f = 1; var g = "1" expect (f == g) .toEqual (true); // true expect (f) .toEqual (g); // falsa expectativa (f) .toBe (g); // false
user1809104
6
Isso está completamente errado. nãotoEqual é o mesmo que . ==
meagar
6
Leia os comentários acima. expect(1).toEqual('1')falha, enquanto 1 == '1'é verdade. toEqualnão tem nada a ver com ==. É como, ===exceto que ele compara objetos de maneira semelhante à comparação por valor.
meagar
33

Para citar o projeto jasmine github,

expect(x).toEqual(y); compara objetos ou primitivas x e y e passa se forem equivalentes

expect(x).toBe(y);compara objetos ou primitivas x e y e passa se forem o mesmo objeto

Tharaka
fonte
14

Analisar o código fonte do Jasmine lança mais luz sobre o problema.

toBeé muito simples e apenas usa o operador de identidade / igualdade estrita ===:

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

toEqual, Por outro lado, é aproximadamente 150 linhas de comprimento e tem um manuseamento especial para construído em objectos como String, Number, Boolean, Date, Error, Elemente RegExp. Para outros objetos, ele compara recursivamente propriedades.

Isso é muito diferente do comportamento do operador de igualdade ==,. Por exemplo:

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

toEqual()compara valores se Primitivo ou conteúdo se Objetos. toBe()compara referências.

O código / conjunto a seguir deve 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);
  });
});
BeingSuman
fonte
1

Pensei que alguém poderia gostar de explicação por exemplo (anotado):

Abaixo, se minha função deepClone () fizer seu trabalho corretamente, o teste (conforme descrito na chamada 'it ()') terá ê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.
    })
})

É claro que esse não é um conjunto de testes completo para o meu deepClone (), pois não testei aqui se o objeto literal na matriz (e o aninhado nela) também possui identidade distinta, mas os mesmos valores.

Jared Tomaszewski
fonte
0

Eu acho que toEqual está verificando profundamente igual, toBe é a mesma referência de 2 variáveis

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

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

Pontos a serem observados:

  • toBe()trata comparações como como Object.is().
  • toEqual()trata comparações como como ===.

É por isso que para tipos primitivos, toBee toEqualnão há muita diferença ao testar a igualdade, mas para tipos de referência como objetos, você prefere usar toEqualpara testar a igualdade.

John Mutuma
fonte