Mocha / Chai expect.to.throw不捕捉抛出错误

我有问题让Chai的expect.to.throw在我的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.
234787 次浏览

你必须传递一个函数给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.'));

你这样做的方式是,你将调用model.get('z')结果传递给expect。但是为了测试是否抛出了一些东西,你必须将一个函数传递给expectexpect将调用它自己。上面使用的bind方法创建了一个新函数,该函数在被调用时将调用model.get,将this设置为model的值,并将第一个参数设置为'z'

bind的一个很好的解释可以在在这里找到。

就像这个答案说一样,你也可以像这样把你的代码包装在一个匿名函数中:

expect(function(){
model.get('z');
}).to.throw('Property does not exist in model schema.');

如果你已经在使用ES6/ES2015,那么你也可以使用箭头函数。它基本上与使用普通匿名函数相同,但更短。

expect(() => model.get('z')).to.throw('Property does not exist in model schema.');

这个问题有很多很多重复,包括没有提到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

你可以使用任何断言库检查特定的错误:

Node . sh

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

< a href = " http://shouldjs.github。io / # should-throws noreferrer“rel = >应< / >

  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 Expect

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

乍一看,这可能令人困惑。就像骑自行车一样,一旦点击,它就会永远“点击”。

来自医生…;)

因为你依赖于this context:

  • 当函数被.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
    

另一种可能的实现,比.bind()解决方案更麻烦,但有助于说明expect()需要一个为覆盖的函数提供this上下文的函数,您可以使用call(),例如:

expect(function() {model.get.call(model, 'z');}).to.throw('...');

我找到了一个很好的方法:

// The test, BDD style
it ("unsupported site", () => {
The.function(myFunc)
.with.arguments({url:"https://www.ebay.com/"})
.should.throw(/unsupported/);
});




// The function that does the magic: (lang:TypeScript)
export const The = {
'function': (func:Function) => ({
'with': ({
'arguments': function (...args:any) {
return () => func(...args);
}
})
})
};

它比我以前的版本更有可读性:

it ("unsupported site", () => {
const args = {url:"https://www.ebay.com/"}; //Arrange
function check_unsupported_site() { myFunc(args) } //Act
check_unsupported_site.should.throw(/unsupported/) //Assert
});