Jasmine JavaScript Testing - toBe vs toEqual

后端 未结 7 1725
不思量自难忘°
不思量自难忘° 2020-11-28 17:32

Let\'s say I have the following:

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

Both of the above tests will pass

相关标签:
7条回答
  • 2020-11-28 18:21

    To quote the jasmine github project,

    expect(x).toEqual(y); compares objects or primitives x and y and passes if they are equivalent

    expect(x).toBe(y); compares objects or primitives x and y and passes if they are the same object

    0 讨论(0)
  • 2020-11-28 18:21

    toEqual() compares values if Primitive or contents if Objects. toBe() compares references.

    Following code / suite should be self explanatory :

    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);
      });
    });
    
    0 讨论(0)
  • 2020-11-28 18:22

    Thought someone might like explanation by (annotated) example:

    Below, if my deepClone() function does its job right, the test (as described in the 'it()' call) will succeed:

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

    Of course this is not a complete test suite for my deepClone(), as I haven't tested here if the object literal in the array (and the one nested therein) also have distinct identity but same values.

    0 讨论(0)
  • 2020-11-28 18:24

    toBe() versus toEqual(): toEqual() checks equivalence. toBe(), on the other hand, makes sure that they're the exact same object.

    I would say use toBe() when comparing values, and toEqual() when comparing objects.

    When comparing primitive types, toEqual() and toBe() will yield the same result. When comparing objects, toBe() is a stricter comparison, and if it is not the exact same object in memory this will return false. So unless you want to make sure it's the exact same object in memory, use toEqual() for comparing objects.

    Check this link out for more info : http://evanhahn.com/how-do-i-jasmine/

    Now when looking at the difference between toBe() and toEqual() when it comes to numbers, there shouldn't be any difference so long as your comparison is correct. 5 will always be equivalent to 5.

    A nice place to play around with this to see different outcomes is here

    Update

    An easy way to look at toBe() and toEqual() is to understand what exactly they do in JavaScript. According to Jasmine API, found here:

    toEqual() works for simple literals and variables, and should work for objects

    toBe() compares with ===

    Essentially what that is saying is toEqual() and toBe() are similar Javascripts === operator except toBe() is also checking to make sure it is the exact same object, in that for the example below objectOne === objectTwo //returns false as well. However, toEqual() will return true in that situation.

    Now, you can at least understand why when given:

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

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

    That is because, as stated in this answer to a different, but similar question, the === operator actually means that both operands reference the same object, or in case of value types, have the same value.

    0 讨论(0)
  • 2020-11-28 18:25

    For primitive types (e.g. numbers, booleans, strings, etc.), there is no difference between toBe and toEqual; either one will work for 5, true, or "the cake is a lie".

    To understand the difference between toBe and toEqual, let's imagine three objects.

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

    Using a strict comparison (===), some things are "the same":

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

    But some things, even though they are "equal", are not "the same", since they represent objects that live in different locations in memory.

    > b === c
    false
    

    Jasmine's toBe matcher is nothing more than a wrapper for a strict equality comparison

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

    is the same thing as

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

    Don't just take my word for it; see the source code for toBe.

    But b and c represent functionally equivalent objects; they both look like

    { foo: { bar: 'baz' } }
    

    Wouldn't it be great if we could say that b and c are "equal" even if they don't represent the same object?

    Enter toEqual, which checks "deep equality" (i.e. does a recursive search through the objects to determine whether the values for their keys are equivalent). Both of the following tests will pass:

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

    Hope that helps clarify some things.

    0 讨论(0)
  • 2020-11-28 18:25

    Looking at the Jasmine source code sheds more light on the issue.

    toBe is very simple and just uses the identity/strict equality operator, ===:

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

    toEqual, on the other hand, is nearly 150 lines long and has special handling for built in objects like String, Number, Boolean, Date, Error, Element and RegExp. For other objects it recursively compares properties.

    This is very different from the behavior of the equality operator, ==. For example:

    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
    
    0 讨论(0)
提交回复
热议问题