首页 文章

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

提问于
浏览
204

我'm having issues getting Chai' s 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();
});

失败:

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.

6 回答

  • 147

    你必须将一个函数传递给 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') 的结果 . 但是为了测试是否抛出某些东西,你必须将一个函数传递给 expectexpect 将调用它自己 . 上面使用的 bind 方法创建一个新函数,调用时将调用 model.get ,其中 this 设置为 model ,第一个参数设置为 'z' .

    可以找到 bind 的一个很好的解释here .

  • 59

    作为this answer says,您也可以将代码包装在这样的匿名函数中:

    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.');
    
  • 281

    这个问题有许多重复,包括没有提到Chai断言库的问题 . 以下是收集在一起的基础知识:

    The assertion must call the function, instead of it evaluating immediately.

    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
    

    You can check for specific errors using any assertion library:

    Node

    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

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

    You must handle exceptions that 'escape' the test

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

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

  • 1

    来自doc ......;的例子

    因为你依赖 this context

    • .throw 调用该函数时丢失

    • 没有办法知道它应该是什么

    你必须使用以下选项之一:

    • wrap 另一个函数内部的方法或函数调用

    • bind 上下文

    // 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
    
  • 73

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

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

相关问题