Jest 中的“toBe”和“toEqual”有啥区别?
Posted
技术标签:
【中文标题】Jest 中的“toBe”和“toEqual”有啥区别?【英文标题】:What is the difference between 'toBe' and 'toEqual' in Jest?Jest 中的“toBe”和“toEqual”有什么区别? 【发布时间】:2017-12-24 23:43:55 【问题描述】: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
在这种情况下会失败?
此外,是否有使用 toBe
和 toEqual
的最佳实践(不仅在 Jest 中,在其他测试框架中也是如此)?
【问题讨论】:
仅供参考:关于这两种方法的文档现在很常见: - jestjs.io/docs/en/expect#toequalvalue - jestjs.io/docs/en/expect#tobevalue 两种方法都在内部使用Object.is
。
【参考方案1】:
它失败了,因为x
和y
是不同的实例,并且不等于(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()
,就是测试。
问题 = 成为 || !toBe;
@OliverShaw toBe
或 toEqual
可以与原语一起使用,但 toBe
特别适用于引用相等。当你想断言它实际上是一个对象的同一个实例时。【参考方案2】:
假设有两个同名玩家,他们都得了 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
我已经针对特定情况编写了此答案,当您了解身份和功能时,您可以在您的场景中实现它。
【讨论】:
【参考方案3】:自从Jest v23 之后,您还拥有toStrictEqual()
解释: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'
【讨论】:
【参考方案4】:有人说.toBe()
和x === y
是一样的,其实还是有一点区别的。 Jest 在做expect(x).toBe(y)
时使用Object.is(x, y)
。
MDN - Object.is()
Jest .toBe source code
除非您要验证值是否与引用相同(例如检查某些内容是否正确进行了深度克隆),否则应始终使用.toEqual()
。即使在 deepclone 示例中,我认为只做expect(x === y).toEqual(true)
只是为了消除对您要做什么的任何困惑。
您不应该期望其他人知道toBe
和toEqual
之间的区别,甚至不应该知道Object.is
的存在以及它与===
的不同之处。为避免通信问题和测试问题,请始终使用.toEqual
,切勿使用.toBe
。
【讨论】:
【参考方案5】:都是关于对象引用的。
.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' ; 让 b = a;
这里,赋值运算符将存储在变量a
中的对象引用复制到b
。
expect(a).toBe(b); // PASSES
断言通过是因为 'a' 和 'b' 指向同一个对象。请注意 name: 'john doe'
不是对象,它是创建对象的指令。对象存在于内存中,并通过存储在变量中的引用进行交互。
【讨论】:
以上是关于Jest 中的“toBe”和“toEqual”有啥区别?的主要内容,如果未能解决你的问题,请参考以下文章