javascript - Mocha/Chai expect.to.throw ไม่จับข้อผิดพลาดที่ถูกขว้าง
ฉันกำลังมีปัญหาในการทำให้ expect.to.throw ของ Chai ทำงานในทดสอบสำหรับแอป node.js ของฉัน การทดสอบมักล้มเหลวกับข้อผิดพลาดที่ถูกโยนออกมา แต่ถ้าฉันห่อกรณีทดสอบด้วย try และ catch และตรวจสอบข้อผิดพลาดที่จับได้ มันก็ทำงาน
expect.to.throw มันไม่ทำงานอย่างที่ฉันคิดไว้หรือเปล่า?
it('should throw an error if you try to get an undefined property', function (done) {
var params = { a: 'test', b: 'test', c: 'test' };
var model = new TestModel(MOCK_REQUEST, params);
// neither of these work
expect(model.get('z')).to.throw('Property does not exist in model schema.');
expect(model.get('z')).to.throw(new Error('Property does not exist in model schema.'));
// this works
try {
model.get('z');
}
catch(err) {
expect(err).to.eql(new Error('Property does not exist in model schema.'));
}
done();
});
ความล้มเหลว:
19 passing (25ms)
1 failing
1) Model Base should throw an error if you try to get an undefined property:
Error: Property does not exist in model schema.
คำตอบ #1
คุณต้องส่งฟังก์ชันไปยัง expect แบบนี้:
expect(model.get.bind(model, 'z')).to.throw('Property does not exist in model schema.');
expect(model.get.bind(model, 'z')).to.throw(new Error('Property does not exist in model schema.'));
ในวิธีที่คุณทำอยู่ คุณกำลังส่ง expect ผลลัพธ์ของการเรียก model.get('z') แต่เพื่อทดสอบว่ามีสิ่งใดถูกโยนหรือไม่ คุณต้องส่งฟังก์ชันให้กับ expect ซึ่ง expect จะเป็นคนเรียกมันเอง วิธี bind ที่ใช้ด้านบนจะสร้างฟังก์ชันใหม่ซึ่งเมื่อถูกเรียกจะเรียก model.get โดยที่ this ถูกตั้งค่าเป็นค่า model และอาร์กิวเมนต์แรกถูกตั้งค่าเป็น 'z'.
คำอธิบายที่ดีเกี่ยวกับ bind สามารถหาได้ที่นี่
คำตอบ #2
ตามที่คำตอบนี้กล่าวไว้ คุณยังสามารถห่อโค้ดของคุณในฟังก์ชันที่ไม่มีชื่อแบบนี้ได้เช่นกัน:
expect(function(){
model.get('z');
}).to.throw('Property does not exist in model schema.');
คำตอบ #3
และหากคุณกำลังใช้ ES6/ES2015 อยู่แล้ว คุณก็สามารถใช้ฟังก์ชันลูกศรได้เช่นกัน ซึ่งโดยพื้นฐานแล้วก็เหมือนกับการใช้ฟังก์ชันนิรนามธรรมดา แต่สั้นกว่า
expect(() => model.get('z')).to.throw('Property does not exist in model schema.');
คำตอบ #4
คำถามนี้มีหลายคำถามที่ซ้ำกันมาก ๆ รวมถึงคำถามที่ไม่ได้กล่าวถึงไลบรารีการยืนยัน Chai ด้วย นี่คือพื้นฐานที่รวบรวมไว้ด้วยกัน:
assert.throws(x.y.z);
// FAIL. x.y.z throws an exception, which immediately exits the
// enclosing block, so assert.throw() not called.
assert.throws(()=>x.y.z);
// assert.throw() is called with a function, which only throws
// when assert.throw executes the function.
assert.throws(function () { x.y.z });
// if you cannot use ES6 at work
function badReference() { x.y.z }; assert.throws(badReference);
// for the verbose
assert.throws(()=>model.get(z));
// the specific example given.
homegrownAssertThrows(model.get, z);
// a style common in Python, but not in JavaScript
คุณสามารถตรวจสอบข้อผิดพลาดเฉพาะได้โดยใช้ไลบรารีตรวจสอบใดก็ได้:
โหนด
assert.throws(() => x.y.z);
assert.throws(() => x.y.z, ReferenceError);
assert.throws(() => x.y.z, ReferenceError, /is not defined/);
assert.throws(() => x.y.z, /is not defined/);
assert.doesNotThrow(() => 42);
assert.throws(() => x.y.z, Error);
assert.throws(() => model.get.z, /Property does not exist in model schema./)
ควร
should.throws(() => x.y.z);
should.throws(() => x.y.z, ReferenceError);
should.throws(() => x.y.z, ReferenceError, /is not defined/);
should.throws(() => x.y.z, /is not defined/);
should.doesNotThrow(() => 42);
should.throws(() => x.y.z, Error);
should.throws(() => model.get.z, /Property does not exist in model schema./)
ชาย เอ็กซ์เพ็คท์
expect(() => x.y.z).to.throw();
expect(() => x.y.z).to.throw(ReferenceError);
expect(() => x.y.z).to.throw(ReferenceError, /is not defined/);
expect(() => x.y.z).to.throw(/is not defined/);
expect(() => 42).not.to.throw();
expect(() => x.y.z).to.throw(Error);
expect(() => model.get.z).to.throw(/Property does not exist in model schema./);
คุณต้องจัดการข้อยกเว้นที่ 'หลุด' ออกจากการทดสอบ
it('should handle escaped errors', function () {
try {
expect(() => x.y.z).not.to.throw(RangeError);
} catch (err) {
expect(err).to.be.a(ReferenceError);
}
});
สิ่งนี้อาจดูสับสนในตอนแรก เหมือนกับการขี่จักรยาน มันเพียงแค่ 'คลิก' ต่อเนื่องเมื่อมันคลิกได้แล้ว
คำตอบ #5
ตัวอย่างจากเอกสาร... ;)
เพราะคุณพึ่งพาบริบท this นี้:
- ซึ่งจะหายไปเมื่อฟังก์ชันถูกเรียกใช้งานโดย .throw
- ไม่มีทางที่มันจะรู้ว่านี่ควรจะเป็นอะไร
คุณต้องใช้ตัวเลือกหนึ่งในนี้:
- ห่อ การเรียกใช้เมธอดหรือฟังก์ชันภายในฟังก์ชันอื่น
ผูก บริบท
// wrap the method or function call inside of another function expect(function () { cat.meow(); }).to.throw(); // Function expression expect(() => cat.meow()).to.throw(); // ES6 arrow function // bind the context expect(cat.meow.bind(cat)).to.throw(); // Bind
