Жасмин тестування JavaScript - toBe vs toEqual


349

Скажімо, у мене є таке:

var myNumber = 5;
expect(myNumber).toBe(5);
expect(myNumber).toEqual(5);

Обидва вищевказані тести пройдуть. Чи є різниця між toBe()і toEqual()коли йдеться про оцінку чисел? Якщо так, коли я повинен використовувати одне, а не друге?


у двох словах: різниці між цими двома при порівнянні примітивів; для об'єктів -> toEqual()буде порівнювати за ключовими / значеннями-змістом; toBe()буде порівнюватися за посиланням на об'єкт.
Андре Елріко

Відповіді:


489

Для примітивних типів (наприклад, чисел, булевих рядків, рядків тощо) різниця між 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

Матч Жасмін - toBeце не що інше, як обгортка для суворого порівняння рівності

expect(c.foo).toBe(b.foo)

те саме, що і

expect(c.foo === b.foo).toBe(true)

Не приймайте моє слово за це; див . вихідний код для toBe .

Але bі cпредставляють функціонально рівнозначні об'єкти; вони обидва схожі

{ foo: { bar: 'baz' } }

Чи не було б чудово, якби ми могли це сказати bі cбули «рівними», навіть якщо вони не представляють один і той же об’єкт?

Введіть toEqual, який перевіряє "глибоку рівність" (тобто здійснює рекурсивний пошук через об'єкти, щоб визначити, чи є значення їхніх ключів еквівалентними). Пройдуть обидва наступні тести:

expect(b).not.toBe(c);
expect(b).toEqual(c);

Сподіваюсь, що допоможе з’ясувати деякі речі.


17
"Для примітивних типів (наприклад, чисел, булевих рядків, рядків тощо) немає різниці між toBe і toEqual" - як виявляється, це не зовсім вірно. expect(0).toBe(-0)пройде, але expect(0).toEqual(-0)провалиться.
мгol

11
tl; dr - toBeвикористовує сувору рівність - порівнювати за посиланням, toEqualвикористовує властивість еквівалентності. Рекомендовано використовувати toEqualдля примітивів
Дреней

1
Отже, кого ми повинні використовувати для примітивів, і чому? Дреней, чому ти рекомендуєш рівний?
Патрік Шалапський

@PatrickSzalapski я можу тільки здогадуватися міркування Denai, але toEqualнабагато більш обережними щодо рівності ( 0 != -0, "hi" = new String("hi")і т.д.), так що я б рекомендував використовувати toEqual тільки , якщо ви на самому справі стурбовані еталонної еквівалентності. Переглянути всі перевірки toEqualв eqметоді можна тут: github.com/jasmine/jasmine/blob/master/src/core/matchers/…
Річка

Я думаю, що краще використовувати toBe при порівнянні примітивів, щоб зберегти накладні витрати, що робиться в toEqual.
ГарфілдКлон

81

toBe()проти toEqual(): toEqual()перевіряє еквівалентність. toBe()з іншого боку, гарантує, що вони точно такий самий об’єкт.

Я б сказав, використовуйте toBe()при порівнянні значень і toEqual()при порівнянні об'єктів.

Якщо порівнювати примітивні типи, toEqual()і toBe()це дасть той же результат. Якщо порівнювати об'єкти, toBe()це суворіше порівняння, і якщо це не той самий об’єкт у пам'яті, це повернеться помилковим. Тому, якщо ви не хочете переконатися, що це абсолютно той самий об’єкт у пам'яті, використовуйте toEqual()для порівняння об'єктів.

Перегляньте це посилання, щоб отримати докладнішу інформацію: http://evanhahn.com/how-do-i-jasmine/

Тепер, коли дивимось на різницю між toBe()чи toEqual()коли мова йде про числа, не повинно бути різниці, якщо ваше порівняння є правильним. 5завжди буде рівнозначним 5.

Приємне місце, щоб пограти з цим, щоб побачити різні результати, є тут

Оновлення

Простий спосіб подивитися toBe()і toEqual()зрозуміти, що саме вони роблять в JavaScript. За даними API Жасмін, тут знайдено :

toEqual () працює для простих літералів і змінних і повинен працювати для об'єктів

toBe () порівнює з ===

За суті, що сказати, toEqual()і toBe()подібні Javascripts ===оператора , за винятком toBe()також перевірки , щоб переконатися , що це той же самий об'єкт, в тому , що на прикладі нижче , objectOne === objectTwo //returns falseа також. Однак toEqual()повернеться істинним у цій ситуації.

Тепер ви можете принаймні зрозуміти, чому, коли вам дають:

var objectOne = {
    propertyOne: str,
    propertyTwo: num    
}

var objectTwo = {
    propertyOne: str,
    propertyTwo: num    
}

expect(objectOne).toBe(objectTwo); //returns false

Це відбувається тому , що, як зазначено в цій відповіді на інший, але подібне питання,=== оператор на самому ділі означає , що обидва операнд посилається на той же об'єкт, або в разі типів значень, має однакове значення.


4
Це дозволяє уникнути відповіді на запитання. Ви пояснюєте, що toEqual()означає, що toEqual()перевіряє еквівалентність , але очевидне наступне питання - це добре, а що означає "еквівалент"? Опис алгоритму, який використовується для визначення "еквівалентності", або, принаймні, приклади випадків, коли поведінка toEqual()і toBe()відрізняються, зробить це більш корисним.
Марк Амері

8
Це не лише не відповідає на питання, але й неправильно . toEqualслід використовувати для глибокого порівняння між об'єктами, а не toBe. jsfiddle.net/bBL9P/67
Lloyd Banks

3
Здається, люди не намагаються перевіряти, чи правильно те, що вони говорять. І Bee, і ToEqual здаються суворими порівняннями. Протестуйте ... Тож у моєму тестуванні я ще не знаходжу різниці. наприклад: var f = 1; var g = "1" очікувати (f == g) .toEqual (true); // справжнє очікувати (f) .toEqual (g); // помилкове очікувати (f) .toBe (g); // false
user1809104

6
Це абсолютно неправильно. toEqualзовсім не те саме, що ==.
meagar

6
Прочитайте коментарі вище. expect(1).toEqual('1')не вдається, хоча 1 == '1'це правда. toEqualне має нічого спільного ==. Це як ===виняток, що він буде порівнювати об'єкти таким чином, як порівняння за вартістю.
meagar

33

Щоб цитувати проект жасминового гітуба,

expect(x).toEqual(y); порівнює об'єкти або примітиви x і y і передає, якщо вони еквівалентні

expect(x).toBe(y);порівнює об'єкти або примітиви x і y і передає, якщо вони є одним і тим же об'єктом


14

Дивлячись на вихідний код Жасмін, проливають більше світла на це питання.

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

2

toEqual()порівнює значення, якщо примітивні або вміст, якщо об'єкти. 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);
  });
});

1

Думав, що комусь може сподобатись пояснення на (анотований) приклад:

Нижче, якщо моя функція 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 (), так як я не перевіряв тут, якщо об'єкт-літерал у масиві (і той, що вкладений у нього) також має чітку ідентичність, але однакові значення.


0

Я думаю, що toEqual перевіряє глибоке рівне, toBe - це те саме, що посилається на 2 змінних

  it('test me', () => {
    expect([] === []).toEqual(false) // true
    expect([] == []).toEqual(false) // true

    expect([]).toEqual([]); // true // deep check
    expect([]).toBe([]); // false
  })

-2

Бали, які слід зазначити:

  • toBe()трактує порівняння, як це Object.is()робить.
  • toEqual()трактує порівняння, як це ===робить.

Ось чому для примітивних типів toBeі toEqualне має великої різниці при тестуванні на рівність, але для референтних типів, таких як об'єкти, ви краще скористаєтеся toEqualдля перевірки рівності.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.