假设我有以下内容:
var myNumber = 5;
expect(myNumber).toBe(5);
expect(myNumber).toEqual(5);
上述两项测试都将通过。在评估数字时,toBe()
和 toEqual()
有区别吗?如果是这样,我什么时候应该使用一个而不是另一个?
toEqual()
将按键/值-内容进行比较; toBe()
将按对象引用进行比较。
对于原始类型(例如数字、布尔值、字符串等),toBe
和 toEqual
没有区别;任何一个都适用于 5
、true
或 "the cake is a lie"
。
为了理解 toBe
和 toEqual
之间的区别,让我们想象三个对象。
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)
不要只相信我的话;见the source code for toBe。
但是 b
和 c
表示功能上等价的对象;他们看起来都像
{ foo: { bar: 'baz' } }
如果我们可以说 b
和 c
是“相等的”,即使它们不代表同一个对象,那不是很好吗?
输入 toEqual
,它检查“深度相等”(即对对象进行递归搜索以确定其键的值是否相等)。以下两个测试都将通过:
expect(b).not.toBe(c);
expect(b).toEqual(c);
希望这有助于澄清一些事情。
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,找到 here:
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
这是因为,如 this answer to a different, but similar question, 中所述,===
运算符实际上意味着两个操作数都引用同一个对象,或者在值类型的情况下,具有相同的值。
toEqual()
检查等价性 来解释 toEqual()
的作用,但下一个明显的问题是好的,那么“等价”是什么意思?用于确定“等价”的算法,或者至少是 toEqual()
和 toBe()
的行为不同的情况的示例,将使这更有用。
toEqual
根本不与 ==
相同。
expect(1).toEqual('1')
失败,而 1 == '1'
为真。 toEqual
与 ==
无关。它与 ===
类似,只是它将以类似于按值比较的方式比较对象。
引用 jasmine github 项目,
期望(x).toEqual(y);比较对象或原语 x 和 y,如果它们是等价的则通过 expect(x).toBe(y);比较对象或原语 x 和 y,如果它们是同一个对象,则通过
查看 Jasmine 源代码可以更清楚地了解这个问题。
toBe
非常简单,只使用身份/严格相等运算符 ===
:
function(actual, expected) {
return {
pass: actual === expected
};
}
另一方面,toEqual
有近 150 行长,对 String
、Number
、Boolean
、Date
、Error
、Element
和 RegExp
等内置对象有特殊处理.对于其他对象,它递归地比较属性。
这与相等运算符 ==
的行为非常不同。例如:
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
toEqual()
如果是 Primitive,则比较值,如果是 Objects,则比较内容。 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 正在检查深度相等,toBe 是 2 个变量的相同引用
it('test me', () => {
expect([] === []).toEqual(false) // true
expect([] == []).toEqual(false) // true
expect([]).toEqual([]); // true // deep check
expect([]).toBe([]); // false
})
认为有人可能喜欢通过(带注释的)示例进行解释:
下面,如果我的 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() 的完整测试套件,因为我没有在这里测试数组中的对象字面量(以及嵌套在其中的对象字面量)是否也具有不同的标识但相同的值。
expect(0).toBe(-0)
将通过,但expect(0).toEqual(-0)
将失败。toBe
使用严格相等 - 通过引用比较,toEqual
使用属性等价。建议将toEqual
用于基元toEqual
对平等(0 != -0
、"hi" = new String("hi")
等)更加谨慎,所以我建议使用toEqual
专门除非您实际上担心参考等效性。在此处查看toEqual
在eq
方法中所做的所有检查:github.com/jasmine/jasmine/blob/master/src/core/matchers/…