Kiểm tra JavaScript Jasmine - toBe vs toEqual


348

Hãy nói rằng tôi có những điều sau đây:

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

Cả hai bài kiểm tra trên sẽ vượt qua. Có sự khác biệt giữa toBe()toEqual()khi nói đến việc đánh giá các con số? Nếu vậy, khi nào tôi nên sử dụng cái này chứ không phải cái kia?


một cách ngắn gọn: không có sự khác biệt giữa hai khi so sánh nguyên thủy; đối với các đối tượng -> toEqual()sẽ so sánh theo khóa / giá trị-nội dung; toBe()sẽ so sánh bằng cách tham chiếu đối tượng.
Andre Elrico

Câu trả lời:


488

Đối với các kiểu nguyên thủy (ví dụ: số, booleans, chuỗi, v.v.), không có sự khác biệt giữa toBetoEqual; hoặc là một sẽ làm việc cho 5, truehoặc "the cake is a lie".

Để hiểu sự khác biệt giữa toBetoEqual, hãy tưởng tượng ba đối tượng.

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

Sử dụng một so sánh nghiêm ngặt ( ===), một số điều là "giống nhau":

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

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

> c.foo === b.foo
true

Nhưng một số thứ, mặc dù chúng "bằng nhau", không "giống nhau", vì chúng đại diện cho các đối tượng sống ở các vị trí khác nhau trong bộ nhớ.

> b === c
false

toBeMatcher của Jasmine không gì khác hơn là một gói để so sánh bình đẳng nghiêm ngặt

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

giống như

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

Đừng hiểu ý tôi; xem mã nguồn cho toBe .

Nhưng bcđại diện cho các đối tượng chức năng tương đương; cả hai trông giống như

{ foo: { bar: 'baz' } }

Sẽ không tuyệt sao nếu chúng ta có thể nói điều đó bc"bằng nhau" ngay cả khi chúng không đại diện cho cùng một đối tượng?

Enter toEqual, kiểm tra "đẳng thức sâu" (nghĩa là tìm kiếm đệ quy thông qua các đối tượng để xác định xem các giá trị cho khóa của chúng có tương đương không). Cả hai bài kiểm tra sau sẽ vượt qua:

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

Hy vọng rằng sẽ giúp làm rõ một số điều.


17
"Đối với các kiểu nguyên thủy (ví dụ: số, booleans, chuỗi, v.v.), không có sự khác biệt giữa toBe và toEqual" - vì hóa ra điều này không hoàn toàn đúng. expect(0).toBe(-0)sẽ vượt qua nhưng expect(0).toEqual(-0)sẽ thất bại.
mgol

11
tl; dr - toBesử dụng bình đẳng nghiêm ngặt - so sánh bằng tham chiếu, toEqualsử dụng tính tương đương. Khuyến nghị sử dụng toEqualcho người nguyên thủy
Drenai

1
Vì vậy, cái nào chúng ta nên sử dụng cho người nguyên thủy, và tại sao? Drenai, tại sao bạn lại giới thiệu toEqual?
Patrick Szalapski

@PatrickSzalapski Tôi chỉ có thể đoán tại luận Denai, nhưng toEqualcó nhiều thận trọng hơn về bình đẳng ( 0 != -0, "hi" = new String("hi"), vv), vì vậy tôi khuyên bạn nên sử dụng toEqual độc quyền , trừ khi bạn đang thực sự lo ngại về tính tương đương tham khảo. Xem tất cả các kiểm tra toEqualthực hiện trong eqphương pháp tại đây: github.com/jasmine/jasmine/blob/master/src/core/matchers/ Kẻ
Sông

Tôi nghĩ sẽ tốt hơn khi sử dụng toBe khi so sánh các nguyên thủy để tiết kiệm chi phí được thực hiện trong toEqual.
GarfieldKlon

81

toBe()so với toEqual(): toEqual()kiểm tra tương đương. toBe()mặt khác, đảm bảo rằng chúng là cùng một đối tượng.

Tôi sẽ nói sử dụng toBe()khi so sánh các giá trị và toEqual()khi so sánh các đối tượng.

Khi so sánh các loại nguyên thủy, toEqual()toBe()sẽ mang lại kết quả tương tự. Khi so sánh các đối tượng, toBe()là một so sánh chặt chẽ hơn và nếu nó không phải là cùng một đối tượng chính xác trong bộ nhớ thì điều này sẽ trả về false. Vì vậy, trừ khi bạn muốn chắc chắn rằng đó là cùng một đối tượng trong bộ nhớ, hãy sử dụng toEqual()để so sánh các đối tượng.

Kiểm tra liên kết này để biết thêm thông tin: http://evanhahn.com/how-do-i-jasmine/

Bây giờ khi nhìn vào sự khác biệt giữa toBe()toEqual()khi nói đến các con số, không nên có bất kỳ sự khác biệt nào miễn là so sánh của bạn là chính xác. 5sẽ luôn tương đương với 5.

Một nơi tốt đẹp để chơi xung quanh với điều này để thấy kết quả khác nhau là ở đây

Cập nhật

Một cách dễ dàng để xem xét toBe()toEqual()là hiểu chính xác những gì họ làm trong JavaScript. Theo API Jasmine, được tìm thấy ở đây :

toEqual () hoạt động cho các biến và chữ đơn giản và nên hoạt động cho các đối tượng

toBe () so sánh với ===

Về cơ bản những gì đang nói là toEqual()toBe()===toán tử Javascripts tương tự, ngoại trừ toBe()cũng đang kiểm tra để đảm bảo rằng đó là cùng một đối tượng, trong ví dụ dưới đây objectOne === objectTwo //returns false. Tuy nhiên, toEqual()sẽ trở lại đúng trong tình huống đó.

Bây giờ, bạn ít nhất có thể hiểu tại sao khi được đưa ra:

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

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

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

Đó là bởi vì, như đã nêu trong câu trả lời này cho một câu hỏi khác nhau, nhưng tương tự, các ===nhà điều hành thực sự có nghĩa rằng cả hai toán hạng tham khảo cùng một đối tượng, hoặc trong trường hợp các loại giá trị, có cùng giá trị.


4
Điều này tránh trả lời câu hỏi. Bạn giải thích điều gì toEqual()bằng cách nói rằng toEqual()kiểm tra sự tương đương , nhưng câu hỏi tiếp theo rõ ràng là ổn, vậy "tương đương" nghĩa là gì? Một mô tả về thuật toán được sử dụng để xác định "tính tương đương", hoặc ít nhất là các ví dụ về các trường hợp hành vi toEqual()toBe()khác nhau, sẽ khiến điều này hữu ích hơn.
Đánh dấu Amery

8
Điều này không chỉ không trả lời câu hỏi mà còn sai . toEqualnên được sử dụng để so sánh sâu giữa các đối tượng, không toBe. jsfiddle.net/bBL9P/67
Lloyd Banks

3
Có vẻ như mọi người không bận tâm kiểm tra xem những gì họ nói là chính xác. Cả toBe và toEqual dường như là những so sánh nghiêm ngặt. Kiểm tra nó ... Vì vậy, trong thử nghiệm của tôi tôi chưa tìm thấy một sự khác biệt. ví dụ: var f = 1; var g = "1" mong đợi (f == g) .toEqual (true); // đúng mong đợi (f) .toEqual (g); // false mong đợi (f) .toBe (g); // false
user1809104

6
Điều này là hoàn toàn sai. toEqualhoàn toàn không giống như ==.
meagar

6
Đọc các ý kiến ​​trên. expect(1).toEqual('1')thất bại, trong khi đó 1 == '1'là sự thật. toEqualkhông có gì để làm với ==. Giống như ===ngoại trừ việc nó sẽ so sánh các đối tượng theo cách tương tự như so sánh theo giá trị.
meagar

33

Để báo giá dự án hoa nhài,

expect(x).toEqual(y); so sánh các đối tượng hoặc nguyên thủy x và y và vượt qua nếu chúng tương đương

expect(x).toBe(y);so sánh các đối tượng hoặc nguyên thủy x và y và vượt qua nếu chúng là cùng một đối tượng


14

Nhìn vào mã nguồn Jasmine làm sáng tỏ hơn về vấn đề này.

toBelà rất đơn giản và chỉ sử dụng toán tử bình đẳng nghiêm ngặt , ===:

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

toEqualMặt khác, có chiều dài gần 150 dòng và có xử lý đặc biệt cho xây dựng trong các đối tượng như String, Number, Boolean, Date, Error, ElementRegExp. Đối với các đối tượng khác, nó so sánh đệ quy các thuộc tính.

Điều này rất khác với hành vi của toán tử đẳng thức ==,. Ví dụ:

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()so sánh các giá trị nếu Nguyên thủy hoặc nội dung nếu Đối tượng. toBe()so sánh tài liệu tham khảo.

Mã / bộ sau đây nên tự giải thích:

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

Nghĩ rằng ai đó có thể thích giải thích bằng ví dụ (chú thích):

Dưới đây, nếu hàm deepClone () của tôi thực hiện đúng chức năng của mình, thử nghiệm (như được mô tả trong lệnh gọi 'it ()') sẽ thành công:

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

Tất nhiên đây không phải là bộ kiểm tra hoàn chỉnh cho deepClone () của tôi, vì tôi chưa thử nghiệm ở đây nếu đối tượng bằng chữ trong mảng (và một đối tượng được lồng trong đó) cũng có danh tính riêng biệt nhưng có cùng giá trị.


0

Tôi nghĩ toEqual đang kiểm tra sâu bằng nhau, toBe là cùng một tham chiếu của 2 biến

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

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

-2

Điểm cần lưu ý:

  • toBe()xử lý so sánh thích cách Object.is()làm.
  • toEqual()xử lý so sánh thích cách ===làm.

Đó là lý do tại sao đối với các kiểu nguyên thủy toBetoEqualkhông có nhiều khác biệt khi kiểm tra sự bằng nhau, nhưng đối với các loại tham chiếu như các đối tượng, bạn muốn sử dụng toEqualđể kiểm tra sự bằng nhau.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.