Jasmine JavaScript Testing - toBe vs toEqual

348

Katakanlah saya memiliki yang berikut ini:

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

Kedua tes di atas akan lulus. Apakah ada perbedaan antara toBe()dan toEqual()kapan harus mengevaluasi angka? Jika demikian, kapan saya harus menggunakan yang satu dan bukan yang lain?

Lloyd Banks
sumber
Singkatnya: tidak ada perbedaan antara keduanya ketika membandingkan primitif; untuk objek -> toEqual()akan dibandingkan dengan kunci / nilai-konten; toBe()akan membandingkan dengan referensi objek.
Andre Elrico

Jawaban:

488

Untuk tipe primitif (mis. Angka, boolean, string, dll.), Tidak ada perbedaan antara toBedan toEqual; salah satu akan bekerja untuk 5, trueatau "the cake is a lie".

Untuk memahami perbedaan antara toBedan toEqual, mari kita bayangkan tiga objek.

var a = { bar: 'baz' },
    b = { foo: a },
    c = { foo: a };

Menggunakan perbandingan yang ketat ( ===), beberapa hal "sama":

> b.foo.bar === c.foo.bar
true

> b.foo.bar === a.bar
true

> c.foo === b.foo
true

Tetapi beberapa hal, meskipun mereka "sama", tidak "sama", karena mereka mewakili objek yang hidup di lokasi yang berbeda dalam memori.

> b === c
false

toBeMatcher Jasmine tidak lebih dari pembungkus untuk perbandingan kesetaraan yang ketat

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

adalah hal yang sama dengan

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

Jangan hanya mengambil kata-kata saya untuk itu; lihat kode sumber untuk toBe .

Tetapi bdan cmewakili objek yang secara fungsional setara; mereka berdua terlihat seperti

{ foo: { bar: 'baz' } }

Bukankah lebih bagus jika kita bisa mengatakan itu bdan c"setara" walaupun mereka tidak mewakili objek yang sama?

Masukkan toEqual, yang memeriksa "kesetaraan mendalam" (yaitu melakukan pencarian rekursif melalui objek untuk menentukan apakah nilai untuk kunci mereka setara). Kedua tes berikut akan lulus:

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

Harapan itu membantu memperjelas beberapa hal.

elreimundo
sumber
17
"Untuk tipe primitif (mis. Angka, boolean, string, dll.), Tidak ada perbedaan antara toBe dan toEqual" - karena ternyata ini tidak sepenuhnya benar. expect(0).toBe(-0)akan lulus tetapi expect(0).toEqual(-0)akan gagal.
mgol
11
tl; dr - toBemenggunakan kesetaraan yang ketat - bandingkan dengan referensi, toEqualmenggunakan kesetaraan properti. Direkomendasikan untuk digunakan toEqualuntuk primitif
Drenai
1
Jadi yang mana yang harus kita gunakan untuk primitif, dan mengapa? Drenai, mengapa Anda merekomendasikan toEqual?
Patrick Szalapski
@PatrickSzalapski Saya hanya bisa menebak alasan Denai, tapi toEqualjauh lebih berhati-hati tentang kesetaraan ( 0 != -0, "hi" = new String("hi"), dll), jadi saya akan merekomendasikan menggunakan toEqual secara eksklusif kecuali Anda benar-benar khawatir tentang referensi kesetaraan. Lihat semua cek yang toEqualdibuat dalam eqmetode di sini: github.com/jasmine/jasmine/blob/master/src/core/matchers/…
River
Saya pikir lebih baik menggunakan toBe ketika membandingkan primitif untuk menyimpan overhead yang dilakukan dalam toEqual.
GarfieldKlon
81

toBe()versus toEqual(): toEqual()memeriksa kesetaraan. toBe(), di sisi lain, memastikan bahwa mereka adalah objek yang sama persis.

Saya akan mengatakan penggunaan toBe()saat membandingkan nilai, dan toEqual()ketika membandingkan objek.

Saat membandingkan tipe primitif, toEqual()dan toBe()akan menghasilkan hasil yang sama. Ketika membandingkan objek, toBe()adalah perbandingan yang lebih ketat, dan jika bukan objek yang sama persis dalam memori ini akan menghasilkan false. Jadi, kecuali Anda ingin memastikan itu adalah objek yang sama persis dalam memori, gunakan toEqual()untuk membandingkan objek.

Lihat tautan ini untuk info lebih lanjut: http://evanhahn.com/how-do-i-jasmine/

Sekarang ketika melihat perbedaan antara toBe()dan toEqual()ketika datang ke angka, seharusnya tidak ada perbedaan selama perbandingan Anda benar. 5akan selalu setara dengan 5.

Tempat yang bagus untuk bermain-main dengan ini untuk melihat hasil yang berbeda ada di sini

Memperbarui

Cara mudah untuk melihat toBe()dan toEqual()memahami apa yang sebenarnya mereka lakukan dalam JavaScript. Menurut Jasmine API, ditemukan di sini :

toEqual () berfungsi untuk literal dan variabel sederhana, dan harus berfungsi untuk objek

toBe () dibandingkan dengan ===

Pada dasarnya apa yang dikatakan adalah toEqual()dan toBe()merupakan ===operator Javascripts yang serupa kecuali toBe()juga memeriksa untuk memastikan itu adalah objek yang sama persis, dalam contoh di bawah ini objectOne === objectTwo //returns falsejuga. Namun, toEqual()akan kembali benar dalam situasi itu.

Sekarang, Anda setidaknya bisa mengerti mengapa ketika diberikan:

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

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

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

Itu karena, sebagaimana tercantum dalam jawaban ini untuk pertanyaan yang berbeda, namun mirip, yang ===operator yang benar-benar berarti bahwa kedua operan referensi objek yang sama, atau dalam hal jenis nilai, memiliki nilai yang sama.

Adjit
sumber
4
Ini menghindari menjawab pertanyaan. Anda menjelaskan apa toEqual()dengan mengatakan bahwa toEqual()memeriksa kesetaraan , tetapi pertanyaan berikutnya yang jelas tidak apa - apa, jadi apa artinya "setara"? Deskripsi algoritma yang digunakan untuk menentukan "ekivalensi", atau setidaknya contoh kasus di mana perilaku toEqual()dan toBe()perbedaan, akan menjadikan ini lebih berguna.
Mark Amery
8
Tidak hanya ini tidak menjawab pertanyaan, tetapi itu salah . toEqualharus digunakan untuk perbandingan mendalam antara objek, bukan toBe. jsfiddle.net/bBL9P/67
Lloyd Banks
3
Sepertinya orang tidak repot-repot menguji apakah yang mereka katakan benar. Baik toBe dan toEqual tampaknya merupakan perbandingan yang ketat. Uji itu ... Jadi dalam pengujian saya, saya belum menemukan perbedaan. misalnya: var f = 1; var g = "1" ekspektasi (f == g) .toEqual (true); // true ekspektasi (f) .toEqual (g); //
ekspektasi
6
Ini sepenuhnya salah. toEqualadalah sama sekali tidak sama dengan ==.
meagar
6
Baca komentar di atas. expect(1).toEqual('1')gagal, sementara 1 == '1'itu benar. toEqualtidak ada hubungannya dengan ==. Ini seperti ===kecuali bahwa itu akan membandingkan objek dengan cara yang mirip dengan perbandingan nilai.
meagar
33

Mengutip proyek jasmine github,

expect(x).toEqual(y); membandingkan objek atau primitif x dan y dan melewati jika mereka setara

expect(x).toBe(y);membandingkan objek atau primitif x dan y dan melewati jika mereka adalah objek yang sama

Tharaka
sumber
14

Melihat kode sumber Jasmine menjelaskan lebih lanjut tentang masalah ini.

toBesangat sederhana dan hanya menggunakan identitas / operator kesetaraan yang ketat, ===:

  function(actual, expected) {
    return {
      pass: actual === expected
    };
  }

toEqual, Di sisi lain, hampir 150 garis panjang dan memiliki penanganan khusus untuk dibangun di objek seperti String, Number, Boolean, Date, Error, Elementdan RegExp. Untuk objek lain itu secara rekursif membandingkan properti.

Ini sangat berbeda dengan perilaku operator persamaan ==,. Sebagai contoh:

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
Tamlyn
sumber
2

toEqual()membandingkan nilai jika Primitif atau konten jika Objek. toBe()membandingkan referensi.

Kode / suite berikut harus jelas:

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);
  });
});
Menjadi Manusia
sumber
1

Pikir seseorang mungkin menyukai penjelasan dengan contoh (beranotasi):

Di bawah, jika fungsi deepClone () saya melakukan tugasnya dengan benar, tes (seperti yang dijelaskan dalam panggilan 'it ()') akan berhasil:

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.
    })
})

Tentu saja ini bukan suite tes lengkap untuk deepClone saya (), karena saya belum menguji di sini jika objek literal dalam array (dan yang bersarang di dalamnya) juga memiliki identitas yang berbeda tetapi nilai yang sama.

Jared Tomaszewski
sumber
0

Saya pikir toEqual memeriksa sama dalam, toBe adalah referensi yang sama dari 2 variabel

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

    expect([]).toEqual([]); // true // deep check
    expect([]).toBe([]); // false
  })
feyzullah yıldız
sumber
-2

Poin yang perlu diperhatikan:

  • toBe()memperlakukan perbandingan seperti bagaimana caranya Object.is().
  • toEqual()memperlakukan perbandingan seperti bagaimana caranya ===.

Itu sebabnya untuk tipe primitif, toBedan toEqualtidak memiliki banyak perbedaan saat menguji kesetaraan, tetapi untuk tipe referensi seperti objek, Anda lebih suka menggunakan toEqualuntuk menguji kesetaraan.

John Mutuma
sumber