ChatGPT解决这个技术问题 Extra ChatGPT

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

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 通过了,因为它进行了深度相等检查。为什么在这种情况下 toBe 会失败?

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

仅供参考:关于这两种方法的文档现在非常普遍:- jestjs.io/docs/en/expect#toequalvalue - jestjs.io/docs/en/expect#tobevalue 并且这两种方法都在内部使用 Object.is

C
CTS_AE

它失败的原因是 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

有什么理由使用 toBe
toBe 还是toBe,这是个问题。
@ThomasChampion 不要开玩笑... toBe() || not.toBe(),即测试。
问题 = 成为 || !成为;
@OliverShaw toBetoEqual 可以与原语一起使用,但 toBe 特别适用于引用相等。当你想断言它实际上是一个对象的同一个实例时。
a
amit77309

假设有两个同名玩家,他们都得了 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 测试身份和 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

我已经为特定情况编写了这个答案,当您了解身份和功能时,您可以在您的场景中实现它。


C
CTS_AE

Jest v23以来,您还拥有toStrictEqual()

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

有一个具有强制执行 toStrictEqual() 的规则的 ESLint plugin for Jesthttps://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'
  }
}

s
snnsnn

这都是关于对象引用的。

.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' } 不是对象,它是创建对象的指令。对象存在于内存中,并通过存储在变量中的引用与之交互。


J
Jaredcheeda

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

MDN - Object.is()

Jest .toBe 源代码

除非您要验证值是否与引用相同(例如检查某些内容是否正确进行了深度克隆),否则应始终使用 .toEqual()。即使在 deepclone 示例中,我认为只需执行 expect(x === y).toEqual(true) 以消除对您要执行的操作的任何混淆,这样会更干净。

您不应该期望其他人知道 toBetoEqual 之间的区别,甚至不应该知道 Object.is 的存在以及它与 === 的区别。为避免通信问题和测试问题,请始终使用 .toEqual,切勿使用 .toBe