web-dev-qa-db-ja.com

Mocha / Chai expect.to.throwが投げられたエラーを捕まえていない

Chaiのexpect.to.throwを私のnode.jsアプリのテストで動作させるのに問題があります。テストはスローされたエラーで失敗し続けますが、私がテストケースをtry and 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.
218
doremi

関数を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に渡しています。しかし、何かがスローされたかどうかをテストするには、expectに関数を渡す必要があります。expectは自分自身を呼び出します。上記のbindメソッドは、呼び出されるとthismodelの値に設定し、最初の引数をmodel.getに設定して'z'を呼び出す新しい関数を作成します。

bindの詳しい説明はこちら にあります

296
Louis

この答えが を言っているように、あなたは単にこのような無名関数であなたのコードをラップすることもできます:

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

また、すでにES6/ES2015を使用している場合は、矢印機能も使用できます。基本的には通常の無名関数を使用するのと同じですが、短くなります。

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

この質問には、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);
  }
});

これは、最初はわかりにくいかもしれません。自転車に乗るのと同じように、クリックすると永久に「クリック」されます。

62
Charles Merriam

doc ...;)の例

なぜならあなたはthiscontextに頼るからです

  • .throwによって関数が呼び出されると、これは失われます。
  • これがどうなるべきかを知る方法がありません。

あなたはこれらのオプションの1つを使わなければなりません:

  • 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
    

もう1つの可能な実装は、.bind()ソリューションより面倒ですが、expect()がカバーされた関数にthisコンテキストを提供する関数を必要とするという点を明確にするのを助けるもの、あなたはcall()を使用できます。

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

1
SeanOlson