Jasmine JavaScript测试-toBe与toEqual


348

假设我有以下几点:

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

以上两个测试都将通过。在评估数字时toBe()和之间有区别toEqual()吗?如果是这样,什么时候应该使用一个而不是另一个?


简而言之:比较基元时两者没有区别;对于对象-> toEqual()将按键/值-内容进行比较;toBe()将按对象引用进行比较。
Andre Elrico

Answers:


488

对于基本类型(例如数字,布尔值,字符串等),toBe和之间没有区别toEqual;任何一个可以为工作5true"the cake is a lie"

要理解之间的区别toBetoEqual,假设三个对象。

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

使用严格的比较(===),有些事情是“相同的”:

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

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

> c.foo === b.foo
true

但是有些东西,即使它们是“相等的”,也不是“相同的”,因为它们代表的是生活在内存中不同位置的对象。

> b === c
false

茉莉花的toBe匹配器不过是严格相等比较的包装器

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

和...一样

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

不要只是相信我的话;请参阅toBe的源代码

但是bc表示功能上等效的对象;他们俩看起来像

{ foo: { bar: 'baz' } }

如果我们可以这样说b并且c即使它们不代表相同的对象又是“相等的” ,那不是很好吗?

Enter toEqual,它检查“深度相等性”(即,在对象中进行递归搜索以确定其键的值是否等效)。以下两个测试都将通过:

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

希望这有助于澄清一些事情。


17
“对于原始类型(例如数字,布尔值,字符串等),toBe和toEqual之间没有区别”-事实证明,这并不完全正确。expect(0).toBe(-0)会通过,但expect(0).toEqual(-0)会失败。
mgol

11
tl; dr- toBe使用严格相等-通过引用进行比较,toEqual使用属性等效。建议toEqual用于基本体
Drenai

1
那么我们应该为基元使用哪一个?为什么呢?德雷奈,为什么推荐平等?
Patrick Szalapski

@PatrickSzalapski我只能猜测德纳在的推理,但toEqual更加谨慎平等(0 != -0"hi" = new String("hi"),等),所以我建议使用toEqual 专门除非你真的关心引用等价。查看所有的检查,toEqual使得在eq这里方法:github.com/jasmine/jasmine/blob/master/src/core/matchers/...

我认为在比较基元时最好使用toBe来节省在toEqual中完成的开销。
GarfieldKlon

81

toBe()vs toEqual()toEqual()检查等效性。toBe()另一方面,请确保它们是完全相同的对象。

我会说toBe()在比较值和toEqual()比较对象时使用。

当比较基本类型,toEqual()toBe()会产生相同的结果。比较对象时,toBe()进行的比较严格,如果与内存中的对象不完全相同,则返回false。因此,除非要确保它与内存中的对象完全相同,否则请toEqual()用于比较对象。

检查此链接以获取更多信息:http : //evanhahn.com/how-do-i-jasmine/

现在,当看着之间的差异toBe(),并toEqual()当它涉及到数字,不应该有任何区别,只要你的比较是正确的。5将始终等同于5

一个很好的地方可以在这里玩耍以查看不同的结果

更新资料

一个简单的方法来看待toBe()toEqual()是了解他们在JavaScript中做什么。根据Jasmine API,在这里找到:

toEqual()适用于简单的文字和变量,并且应适用于对象

toBe()与 ===

本质上说的是toEqual()并且toBe()是类似的Javascripts ===运算符,除了toBe()还要检查以确保它是完全相同的对象,在下面的示例中objectOne === objectTwo //returns false也是如此。但是,toEqual()在那种情况下将返回true。

现在,您至少可以理解为什么给出以下原因:

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

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

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

这是因为,在说明这个答案不同,但类似的问题,===运营商实际上意味着两个操作数引用同一个对象,或在值类型的情况下,具有相同的值。


4
这避免了回答问题。您toEqual()通过说toEqual()检查等价来解释什么,但是显而易见的下一个问题是可以的,那么“等价”是什么意思?该算法的描述用于确定“对等”,或在其中的行为箱子至少实例toEqual()toBe()不同,会使这个更加有用。
Mark Amery

8
这不仅不能回答问题,而且是错误的toEqual应该用于对象之间的深度比较,而不是toBejsfiddle.net/bBL9P/67
劳埃德银行

3
似乎人们不会费心去测试他们说的话是否正确。toBe和toEqual似乎都是严格的比较。测试它...所以在我的测试中,我还没有发现任何不同。例如:var f = 1; var g =“ 1” Expect(f == g).toEqual(true); // true true(f).toEqual(g); // false false(f).toBe(g); // false
user1809104

6
这是完全错误的。toEqual完全不同==
meagar

6
阅读上面的评论。expect(1).toEqual('1')失败,而1 == '1'事实如此。toEqual与无关==。就像===它会以类似于按值比较的方式比较对象一样。
meagar

33

引用jasmine github项目,

expect(x).toEqual(y); 比较对象或基元x和y,如果它们等效则通过

expect(x).toBe(y);比较对象或基元x和y, 如果它们是同一对象则通过


14

查看Jasmine源代码可以更清楚地了解这个问题。

toBe非常简单,只使用标识/严格相等运算符===

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

toEqual,而另一方面,长近150线,具有特殊处理的内置状物体StringNumberBooleanDateErrorElementRegExp。对于其他对象,它递归比较属性。

这与相等运算符的行为非常不同==。例如:

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

2

toEqual()如果是原始,则比较值;如果是对象,则比较内容。 toBe()比较参考。

以下代码/套件应该很容易说明:

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

以为有人可能喜欢通过(带注释)示例进行解释:

下面,如果我的deepClone()函数正确完成了工作,则测试(如“ it()”调用中所述)将成功:

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

当然,对于我的deepClone()来说,这不是一个完整的测试套件,因为我在这里没有测试过数组中的对象文字(以及嵌套在其中的对象)是否也具有不同的标识但具有相同的值。


0

我认为toEqual正在检查深度相等,toBe是2变量的相同引用

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

    expect([]).toEqual([]); // true // deep check
    expect([]).toBe([]); // false
  })

-2

注意事项:

  • toBe()像进行比较一样对待比较Object.is()
  • toEqual()像进行比较一样对待比较===

这就是为什么对于原始类型,toBe并且toEqual在测试相等性时并没有太大区别的原因,但是对于对象等引用类型,您宁愿使用它toEqual来测试相等性。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.