Jest中的“toBe”和“toEqual”有什么区别?

bt1cpqcv  于 2023-05-11  发布在  Jest
关注(0)|答案(5)|浏览(342)

Jest文档如下:
toBe只是检查一个值是否是你所期望的。它使用===来检查严格相等。
对于toEqual
如果要检查两个对象是否具有相同的值,请使用.toEqual。这个匹配器递归地检查所有字段的相等性,而不是检查对象的身份-这也被称为“深度相等”。例如,toEqual和toBe在这个测试套件中的行为不同,因此所有测试都通过。

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

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

在这种情况下,toEqual通过,但toBe失败。我理解toEqual通过是因为它做了一个 deep equal 检查。为什么toBe在这种情况下会失败?
另外,是否有使用toBetoEqual的最佳实践(不仅在Jest中,而且在其他测试框架中也是如此)?

carvr3hs

carvr3hs1#

它失败的原因是xy是不同的示例,不像(x === y) === false中那样相等。您可以使用toBe来处理字符串、数字或布尔值等原语,其他所有内容都可以使用toEqual。举个例子

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

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

即使是空的物体也不相等

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

xwbd5t1u2#

假设有两个同名的球员,他们都得分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

我已经写了这个答案的特定情况下,当你得到这个想法的身份和功能,你可以实现它在您的场景。

nlejzf6q

nlejzf6q3#

这都是关于对象引用的。
.toBe比较原始值或检查对象示例的引用标识,而toEqual查找深度相等。

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

第二个Assert失败,因为它们是不同的示例,即使它们完全相等。记住,对象文字语法创建了基对象的一个新示例。

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

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

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

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

50few1ms

50few1ms4#

你也有toStrictEqual()自Jest v23
说明:https://jestjs.io/docs/en/expect#tostrictequalvalue
有一个ESLint plugin for Jest,它有一个强制执行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'
  }
}
yizd12fk

yizd12fk5#

有一些人说.toBe()x === y是一样的,但实际上略有不同。Jest在执行expect(x).toBe(y)时使用Object.is(x, y)

除非你正在验证一个值是否与一个引用相同(比如检查某个东西是否正确地被深度克隆),否则你应该总是使用.toEqual()。即使在deepclone示例中,我认为只执行expect(x === y).toEqual(true)更清晰,只是为了消除对您正在尝试做的事情的任何混淆。
您不应该期望其他人知道toBetoEqual之间的区别,或者甚至知道Object.is的存在以及它与===的区别。为了避免通信问题和测试问题,请始终使用.toEqual,不要使用.toBe
我已经写了一个更详细的版本作为博客文章:

相关问题