การทดสอบ JavaScript ของจัสมิน - toBe กับ toEqual


349

สมมติว่าฉันมีดังต่อไปนี้:

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

ทั้งการทดสอบข้างต้นจะผ่าน มีความแตกต่างระหว่างtoBe()และtoEqual()เมื่อมันมาถึงการประเมินตัวเลข? ถ้าเป็นเช่นนั้นฉันควรใช้อันใดอันหนึ่ง


สั้น: ไม่มีความแตกต่างระหว่างทั้งสองเมื่อเปรียบเทียบแบบดั้งเดิม; สำหรับวัตถุ -> toEqual()จะเปรียบเทียบโดยคีย์ / ค่าเนื้อหา toBe()จะเปรียบเทียบโดยการอ้างอิงวัตถุ
Andre Elrico

คำตอบ:


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)จะล้มเหลว
mgol

11
tl; dr - toBeใช้ความเท่าเทียมกันที่เข้มงวด - เปรียบเทียบโดยการอ้างอิงtoEqualใช้การเทียบเท่าคุณสมบัติ แนะนำให้ใช้toEqualสำหรับดึกดำบรรพ์
Drenai

1
แล้วเราควรใช้อันใดกับสิ่งที่เป็นพื้นฐานและทำไม Drenai ทำไมคุณถึงแนะนำถึง Equal?
Patrick Szalapski

@PatrickSzalapski ฉันเท่านั้นที่สามารถคาดเดาเหตุผล Denai แต่toEqualเป็นความระมัดระวังมากขึ้นเกี่ยวกับความเท่าเทียมกัน ( 0 != -0, "hi" = new String("hi")ฯลฯ ) ดังนั้นผมจึงขอแนะนำให้ใช้toEqual เฉพาะถ้าคุณกำลังกังวลเกี่ยวกับความเท่าเทียมกันจริงอ้างอิง ดูการตรวจสอบทั้งหมดที่toEqualทำในeqวิธีการที่นี่: github.com/jasmine/jasmine/blob/master/src/core/matchers/…
แม่น้ำ

ฉันคิดว่ามันจะดีกว่าถ้าใช้ toBe เมื่อเปรียบเทียบแบบดั้งเดิมเพื่อประหยัดค่าใช้จ่ายที่ทำใน toqual
GarfieldKlon

81

toBe()กับtoEqual(): toEqual()ตรวจสอบความเท่าเทียมกัน toBe()ในทางกลับกันตรวจสอบให้แน่ใจว่าพวกเขาเป็นวัตถุเดียวกันแน่นอน

ฉันจะบอกว่าใช้toBe()เมื่อเปรียบเทียบค่าและtoEqual()เมื่อเปรียบเทียบวัตถุ

เมื่อเปรียบเทียบประเภทดั้งเดิมtoEqual()และtoBe()จะให้ผลลัพธ์เดียวกัน เมื่อเปรียบเทียบวัตถุtoBe()คือการเปรียบเทียบที่เข้มงวดยิ่งขึ้นและหากไม่ใช่วัตถุเดียวกันที่แน่นอนในหน่วยความจำสิ่งนี้จะส่งคืนค่าเท็จ ดังนั้นหากคุณไม่ต้องการให้แน่ใจว่าเป็นวัตถุเดียวกันในหน่วยความจำให้ใช้toEqual()สำหรับเปรียบเทียบวัตถุ

ตรวจสอบลิงก์นี้เพื่อรับข้อมูลเพิ่มเติม: http://evanhahn.com/how-do-i-jasmine/

ตอนนี้เมื่อดูความแตกต่างระหว่างtoBe()และtoEqual()เมื่อมันมาถึงตัวเลขไม่ควรมีความแตกต่างตราบใดที่การเปรียบเทียบของคุณถูกต้อง มักจะเทียบเท่ากับ55

สถานที่ที่ดีในการเล่นกับสิ่งนี้เพื่อดูผลลัพธ์ที่แตกต่างอยู่ที่นี่

ปรับปรุง

วิธีง่ายๆในการดูtoBe()และtoEqual()เข้าใจสิ่งที่พวกเขาทำใน JavaScript ตาม Jasmine 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()แตกต่างกันจะทำให้มีประโยชน์มากขึ้น
Mark Amery

8
ไม่เพียงแค่นี้ไม่ตอบคำถาม แต่มันเป็นเรื่องที่ไม่ถูกต้อง ควรจะใช้สำหรับการเปรียบเทียบลึกระหว่างวัตถุไม่ toEqual jsfiddle.net/bBL9P/67toBe
Lloyd Banks

3
ดูเหมือนว่าผู้คนจะไม่รบกวนการทดสอบว่าสิ่งที่พวกเขาพูดนั้นถูกต้องหรือไม่ ทั้ง toBe และ toqual ดูเหมือนจะเป็นการเปรียบเทียบที่เข้มงวด ทดสอบ ... ดังนั้นในการทดสอบของฉันฉันยังไม่พบความแตกต่าง ตัวอย่างเช่น: var f = 1; var g = "1" คาดหวัง (f == g) .toEqual (จริง); // จริงคาดหวัง (f) .toEqual (g); // คาดหวังที่ผิดพลาด (f) .toBe (g); // false
user1809104

6
นี่เป็นสิ่งที่ผิดอย่างสิ้นเชิง toEqualคือไม่ได้เลย==เช่นเดียวกับ
meagar

6
อ่านความคิดเห็นข้างต้น expect(1).toEqual('1')ล้มเหลวในขณะที่1 == '1'เป็นจริง มีอะไรจะทำอย่างไรกับtoEqual ==มันเหมือนกับ===ว่ามันจะเปรียบเทียบวัตถุในลักษณะที่คล้ายคลึงกับการเปรียบเทียบตามค่า
meagar

33

เพื่ออ้างถึงโครงการดอกมะลิ Github

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

ฉันคิดว่า toqual กำลังตรวจสอบความลึกเท่ากับ, 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เพื่อทดสอบความเท่าเทียมกัน

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.