在玩笑中,“成为”和“平等”的区别是什么?

Jest 的文件如下:

ToBe 只是检查一个值是否符合您的期望,它使用 = = = 来检查严格的相等性。

至于 toEqual:

使用。当你想检查两个对象是否具有相同的值时,可以使用。这个匹配器递归地检查所有字段的相等性,而不是检查对象标识ーー这也称为“深度相等”。例如,toEqualandtoBe 在这个测试套件中的行为不同,所以所有的测试都能通过。

const x = { a: { b: 3 } };
const y = { a: { b: 3 } };


expect(x).toEqual(y);
expect(x).toBe(y);

在这种情况下,toEqual通过,但 toBe失败。我知道 toEqual通过是因为它做了 非常平等检查。为什么 toBe在这种情况下会失败?

此外,是否有使用 toBetoEqual的最佳实践(不仅在 Jest 中,而且在其他测试框架中也有) ?

105249 次浏览

它失败的原因是 xy是不同的实例,不等于在 (x === y) === false。对于字符串、数字或布尔值之类的原语,可以使用 toBe,对于其他所有使用 toEqual的内容也可以使用 toBe。比如说

x = 4
y = 4
x === y // true


x = 'someString'
y = 'someString'
x === y // true

即使是空对象也不相等

x = {}
y = {}
x === y //false

Jest v23开始你也有 toStrictEqual()

解说: https://jestjs.io/docs/en/expect#tostrictequalvalue

有一个 用于 Jest 的 ESLint 插件,它有一个强制执行 toStrictEqual()的规则: https://github.com/jest-community/eslint-plugin-jest/blob/master/docs/rules/prefer-strict-equal.md

npm install --save-dev eslint-plugin-jest

// .eslintrc.js
module.exports = {
extends: [
'plugin:jest/recommended'
],


rules: {
'jest/prefer-strict-equal': 'error'
}
}

假设有两个同名球员,他们都得了20分。

let player1 = {
name: "Amit",
score: 20,
}


let player2 = {
name: "Amit",
score: 20,
}

现在我有一个函数,它给了我第一个参与者。

function getFirstPlayer(player1,player2){
return player1;
}

如何测试这个函数?

# 1st way
expect(getFirstPlayer(player1,player2)).toBe(player1); // Passes
expect(getFirstPlayer(player1,player2)).not.toBe(player2); // Passes


# 2nd way
expect(getFirstPlayer(player1,player2)).toEqual(player1); // Pases
expect(getFirstPlayer(player1,player2)).not.toEqual(player2); // Fails

toBe测试 Identity 和 toEqual测试特性。所以双胞胎孩子可以有相同的特征,但是他们的真实身份是不同的。 这个函数的设计方法应该使用 toBe

现在我有另一个增加玩家分数的函数。

function addScore(player,scoreToAdd){
player.score += scoreToAdd;
}

如何测试这个函数?

# 1st way
addScore(player1,20);
expect(player1).toBe({name:"Amit", score:40});  // Fails


# 2nd way
addScore(player1,20);
expect(player1).toEqual({name:"Amit", score:40});  // Passes

你有没有注意到,在第一种方式,我们传递一个新的球员像实体在右手边。player1有没有可能与新创建的实体具有相同的身份?没有。所以在这种情况下 toBe总是会失败。

第二种方法就像在 toEqual中我们比较特性一样,在这里 player1和新创建的实体有相同的特性。

注意: 在 javascript 的上下文中,像 "Amit"这样的原始值本身就是标识

expect("Amit").toBe("Amit") // Passes

我已经针对特定情况编写了这个答案,当您了解了身份和特性的概念后,您可以在您的场景中实现它。

有一些人说 .toBe()x === y是一样的,但实际上它们稍有不同。Jest 在做 expect(x).toBe(y)的时候使用 Object.is(x, y)

除非要验证某个值是否与引用相同(例如在检查某个内容是否被正确深度克隆时) ,否则应始终使用 .toEqual()。甚至在深度克隆的例子中,我认为仅仅执行 expect(x === y).toEqual(true)就可以消除任何关于您正在尝试做什么的混淆,这样做更清楚。

你不应该指望别人知道 toBetoEqual之间的区别,或者甚至知道 Object.is的存在以及它与 ===的区别。为了避免通信问题和测试问题,始终使用 .toEqual,永远不要使用 .toBe

它完全是关于对象引用的。

.toBe比较基元值或检查对象实例的引用标识,而 toEqual查找深度相等性。

expect({ name: 'john doe' }).toEqual({ name: 'john doe'}); // PASSES
expect({ name: 'john doe' }).toBe({ name: 'john doe'});    // FAILS

第二个断言失败是因为它们是不同的实例,即使它们是完全相等的。请记住,对象文本语法创建基对象的新实例。

let a = { name: 'john doe' };
let b = a;

在这里,赋值操作符将存储在变量 a中的对象引用复制到 b

expect(a).toBe(b); // PASSES

断言通过是因为‘ a’和‘ b’指向同一个对象。请注意,{ name: 'john doe' }不是一个对象,而是一条创建对象的指令。对象存储在内存中,并通过它们存储在变量中的引用进行交互。