Mocha/Chai期待.没有抓住抛出的错误

dor*_*emi 238 javascript mocha.js node.js chai

我有问题让Chai expect.to.throw在我的node.js应用程序的测试中工作.测试在抛出错误时保持失败,但是如果我在try中包装测试用例并捕获并断言捕获的错误,则它可以工作.

难道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();
});
Run Code Online (Sandbox Code Playgroud)

失败:

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.
Run Code Online (Sandbox Code Playgroud)

Lou*_*uis 318

你必须传递一个功能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.'));
Run Code Online (Sandbox Code Playgroud)

你正在这样做,你正在转移到调用expect结果model.get('z').但是为了测试是否抛出了某些东西,你必须将一个函数传递给expect它,expect它将调用自己.在bind上面使用方法创建一个其中要求将调用时新功能model.getthis集到的值model,并设置为第一个参数'z'.

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

  • 钱币.为什么文档(http://chaijs.com/api/bdd/#throw)没有演示绑定的这种用法?似乎`to.throw`最常见的测试场景是测试函数中的特定条件,这需要使用无效的状态/参数调用该函数.(就此而言......为什么chaijs.com的深层链接实际上不是深层链接?) (45认同)
  • 请注意,此功能(截至2017年9月)不适用于异步功能:请参阅https://github.com/chaijs/chai/issues/882#issuecomment-322131680和相关讨论。 (3认同)

twi*_*wiz 165

正如这个答案所说,你也可以将代码包装在一个匿名函数中,如下所示:

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

  • 这不适用于异步函数调用.假设model.get是异步,返回promise.但是它会引发错误.如果我尝试上述方法,那就是"Timing out",因为我们必须将"完成"通知给mocha.同时,我不能尝试`expect(function(){model.get('z');}).to.throw('属性在模型模式中不存在.').notify(done); `因为没有通知方法. (5认同)
  • 感谢twiz的回复。我们在集成环境中工作,using模块负责捕获异常。因此,问题是当我们尝试运行单元测试用例时。最后,我们使用下面的方法使它正常工作:catch(err){Expect(err).equal('Error message to checked'); done(); }` (2认同)

Dan*_* T. 83

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

expect(() => model.get('z')).to.throw('Property does not exist in model schema.');
Run Code Online (Sandbox Code Playgroud)

  • @Relic 是的,非常正确。这也是箭头函数的一大优势。箭头函数从创建它们的作用域“继承”“this”。通常这可能是一个优势,因为它避免了手动将函数“绑定”到它们的“this”对象的需要。 (2认同)

Cha*_*iam 70

这个问题有许多重复,包括没有提到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
Run Code Online (Sandbox Code Playgroud)

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

节点

  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./)
Run Code Online (Sandbox Code Playgroud)

应该

  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./)
Run Code Online (Sandbox Code Playgroud)

柴期待

  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./);
Run Code Online (Sandbox Code Playgroud)

您必须处理"逃避"测试的异常

it('should handle escaped errors', function () {
  try {
    expect(() => x.y.z).not.to.throw(RangeError);
  } catch (err) {
    expect(err).to.be.a(ReferenceError);
  }
});
Run Code Online (Sandbox Code Playgroud)

起初这看起来很混乱.就像骑自行车一样,只需点击一下就可以"点击".


Mic*_*ský 7

doc中的示例...;)

因为您依赖于此上下文

  • .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
    
    Run Code Online (Sandbox Code Playgroud)