javascript - Mocha/Chai expect.to.throw fångar inte kastade fel
Jag har problem med att få Chais expect.to.throw att fungera i ett test för min node.js-app. Testet fortsätter att misslyckas på det kastade felet, men om jag omsluter testfallet med try och catch och gör en assertion på det fångade felet, fungerar det.
Fungerar expect.to.throw inte som jag tror att det borde eller något?
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();
});
Misslyckandet:
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.
Svar #1
Du måste skicka en funktion till expect. Så här:
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.'));
På det sätt du gör det passerar du till expect resultatet av att anropa model.get('z'). Men för att testa om något kastas, måste du passa en funktion till expect, som expect själv kommer att anropa. bind-metoden som används ovan skapar en ny funktion som när den anropas kommer att anropa model.get med this satt till värdet av model och det första argumentet satt till 'z'.
En bra förklaring av bind kan hittas här.
Svar #2
Som detta svar säger kan du också bara omsluta din kod i en anonym funktion på detta sätt:
expect(function(){
model.get('z');
}).to.throw('Property does not exist in model schema.');
Svar #3
Och om du redan använder ES6/ES2015 kan du också använda en pilfunktion. Det är i princip samma sak som att använda en vanlig anonym funktion men kortare.
expect(() => model.get('z')).to.throw('Property does not exist in model schema.');
Svar #4
Denna fråga har många, många dubbletter, inklusive frågor som inte nämner Chai-assertionsbiblioteket. Här är grunderna samlade tillsammans:
Påståendet måste anropa funktionen, istället för att det utvärderas omedelbart.
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
Du kan kontrollera efter specifika fel med vilket påståendebibliotek som helst:
Nod
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./)
Bör
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./)
Chai Förvänta
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./);
Du måste hantera undantag som 'undkommer' testet
it('should handle escaped errors', function () {
try {
expect(() => x.y.z).not.to.throw(RangeError);
} catch (err) {
expect(err).to.be.a(ReferenceError);
}
});
Detta kan se förvirrande ut vid första anblicken. Precis som att cykla, så 'klickar' det bara för alltid när det väl klickar.
Svar #5
exempel från doc... ;)
eftersom du förlitar dig på this-kontexten:
- som går förlorad när funktionen anropas av .throw
- det finns inget sätt för det att veta vad detta är tänkt att vara
du måste använda ett av dessa alternativ:
- wrappa metod- eller funktionsanropet inuti en annan funktion
bind kontexten
// 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
