Jasmine JavaScript测试- toBe vs toEqual

假设我有以下内容:

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

以上两个测试都将通过。在计算数字时,toBe()toEqual()之间有区别吗?如果是的话,什么时候我应该使用其中一种而不是另一种?

189785 次浏览

toBe()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()是类似的javascript ===操作符,除了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

这是因为,正如这是对另一个不同但相似问题的答案,中所述,===操作符实际上意味着两个操作数引用同一个对象,或者在值类型的情况下,具有相同的值。

引用jasmine github项目,

expect(x).toEqual(y);比较对象或原语x和y和 如果它们相等,则传递

expect(x).toBe(y);比较对象或原语x和y并传递 如果它们是相同的对象

对于基本类型(例如数字、布尔值、字符串等),toBetoEqual之间没有区别;任何一个都适用于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

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

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

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

不要只相信我的话;看到toBe的源代码

但是bc表示功能等效的对象;它们看起来都像

{ foo: { bar: 'baz' } }

如果我们可以说bc是“相等的”,那不是很好吗?即使它们不代表同一个对象?

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

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

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

查看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

我想有人可能会喜欢用(注释的)例子来解释:

下面,如果我的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()的完整测试套件,因为我没有在这里测试数组中的对象文字(以及其中嵌套的对象)是否也具有不同的标识但相同的值。

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

我认为toEqual是检查deep equal, toBe是2个变量的相同引用

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


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