ジャスミンでエラーがスローされることを期待するテストを書く方法は?


490

エラーが予想されるJasmine Test Frameworkのテストを記述しようとしています。現時点では、GitHubのJasmine Node.js統合を使用しています

私のノードモジュールには、次のコードがあります。

throw new Error("Parsing is not possible");

今、私はこのエラーを期待するテストを書こうとします:

describe('my suite...', function() {
    [..]
    it('should not parse foo', function() {
    [..]
        expect(parser.parse(raw)).toThrow(new Error("Parsing is not possible"));
    });
});

私もError()いくつかの他のバリアントを試しましたが、それを機能させる方法を理解できませんでした。


4
テストされている関数に引数を渡すには、無名関数を使用せずに、試してくださいFunction.bindstackoverflow.com/a/13233194/294855
Danyal Aytekin

回答:


802

関数をexpect(...)呼び出しに渡す必要があります。ここにあるコード:

// incorrect:
expect(parser.parse(raw)).toThrow(new Error("Parsing is not possible"));

結果をに渡そうとして実際に呼び出そ うとしていますparser.parse(raw)expect(...)

代わりに無名関数を使用してみてください:

expect( function(){ parser.parse(raw); } ).toThrow(new Error("Parsing is not possible"));

28
あなたも引数を渡す必要がない場合、あなたはまた、単に期待する関数を渡すことができます:expect(parser.parse).toThrow(...)
SubmittedDenied

60
役立つヒント:を呼び出すだけexpect(blah).toThrow()です。引数がない場合、それがスローすることを確認することを意味します。文字列の照合は必要ありません。次も参照してください:stackoverflow.com/a/9525172/1804678
Jess

1
私の意見では、無名関数でラップするときのテストの意図に関してはより明白です。また、たとえば、ターゲット関数にパラメーターを渡してスローする必要がある場合でも、すべてのテストで一貫性が保たれます。
Beez 2014

10
@SubmittedDenied:これは一般的に機能しません!をparser.parse使用する場合this、コンテキストなしで渡すと予期しない結果が生じます。を渡すこともできますがparser.parse.bind(parser)、正直なところ、匿名関数の方がエレガントです。
mhelvens、2015年

2
@LanceKindはネクロに申し訳ありませんが、関数を渡さなければならない理由は、値が評価され、expectに渡される前に例外をスローするためです。
1gLassitude

68

あなたが使用しています:

expect(fn).toThrow(e)

ただし、関数のコメントを確認する場合(期待されるのは文字列です):

294 /**
295  * Matcher that checks that the expected exception was thrown by the actual.
296  *
297  * @param {String} expected
298  */
299 jasmine.Matchers.prototype.toThrow = function(expected) {

おそらく次のように書くべきでしょう(ラムダ-匿名関数を使用):

expect(function() { parser.parse(raw); } ).toThrow("Parsing is not possible");

これは、次の例で確認されています。

expect(function () {throw new Error("Parsing is not possible")}).toThrow("Parsing is not possible");

Douglas Crockfordは、 "throw new Error()"(プロトタイピング方法)を使用する代わりに、このアプローチを強くお勧めします。

throw {
   name: "Error",
   message: "Parsing is not possible"
}

3
実際にコードtoThrowを見ると、幸いにも例外オブジェクトまたは文字列のいずれかを受け取ります。たとえば、expected.messageへの呼び出しを確認してください。
ピートホジソン

1
メッセージプロパティを持たない文字列の副作用として文字列を許可するように継ぎ合わせます
mpapis

1
働いてくれてありがとう。私はまだピートの答えを受け入れました、彼の答えが私にラムダを使わなければならないことを私にもっとはっきりさせたので。まだ+1 :-)ありがとう!
echox

16
エラーではなくオブジェクトをスローした場合(下の例のように)、それをサポートするブラウザでスタックトレースを取得できません。
kybernetikos 2012年

2
@kybernetikosは驚くべきことに、完全に真実ではありません。非Errorjsfiddle.net/k1mxey8j)をスローした場合でも、Chromeコンソールにスタックトレースが出力されます。ただし、もちろん、スローされたオブジェクトには.stackプロパティがありません。これは、自動エラー報告を設定する場合に重要になることがあります。
Mark Amery、2015

24

唯一の目的が別のものをラップすることである匿名関数を作成するよりもエレガントなソリューションは、es5のbind関数を使用することです。bind関数は、呼び出されたときに、thisキーワードが指定された値に設定された新しい関数を作成します。指定された引数のシーケンスは、新しい関数が呼び出されたときに指定された引数に先行します。

の代わりに:

expect(function () { parser.parse(raw, config); } ).toThrow("Parsing is not possible");

検討してください:

expect(parser.parse.bind(parser, raw, config)).toThrow("Parsing is not possible");

バインド構文を使用すると、さまざまなthis値を持つ関数をテストできます。私の意見では、テストが読みやすくなります。参照:https : //stackoverflow.com/a/13233194/1248889


23

JasmineのtoThrowマッチャーを次のものに置き換えます。これにより、例外の名前プロパティまたはそのメッセージプロパティを照合できます。私にとっては、次のことができるので、これによりテストの記述が簡単になり、脆弱性が少なくなります。

throw {
   name: "NoActionProvided",
   message: "Please specify an 'action' property when configuring the action map."
}

そして、以下でテストします:

expect (function () {
   .. do something
}).toThrow ("NoActionProvided");

これにより、後でテストを中断することなく例外メッセージを微調整することができます。重要なのは、予期されたタイプの例外をスローしたことです。

これは、これを可能にするtoThrowの置き換えです。

jasmine.Matchers.prototype.toThrow = function(expected) {
  var result = false;
  var exception;
  if (typeof this.actual != 'function') {
    throw new Error('Actual is not a function');
  }
  try {
    this.actual();
  } catch (e) {
    exception = e;
  }
  if (exception) {
      result = (expected === jasmine.undefined || this.env.equals_(exception.message || exception, expected.message || expected) || this.env.equals_(exception.name, expected));
  }

  var not = this.isNot ? "not " : "";

  this.message = function() {
    if (exception && (expected === jasmine.undefined || !this.env.equals_(exception.message || exception, expected.message || expected))) {
      return ["Expected function " + not + "to throw", expected ? expected.name || expected.message || expected : " an exception", ", but it threw", exception.name || exception.message || exception].join(' ');
    } else {
      return "Expected function to throw an exception.";
    }
  };

  return result;
};

4
良いアプローチですが、{name: '...'、message: '...'}はJavaScriptの適切なErrorオブジェクトですか?
Marc

1
素敵なコメント@Marc。そうです、nameプロパティは標準ではありません。 developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…、しかしそれはそんなに間違っているのですか?
ジェス

4
@ジェイク!私はより良い方法を見つけました!!!! あなたは単に呼び出すことができますexpect(blah).toThrow()。引数がない場合、それがスローすることを確認することを意味します。文字列の照合は必要ありません。次も参照してください:stackoverflow.com/a/9525172/1804678
Jess

5
ありがとうジェス-それは本当ですが、それはTypeErrorのような他のいくつかのエラーを投げているかもしれません、そして私のテストは実際のバグを隠して誤ってパスします。
ジェイク

4
RegExをtoThrow()の引数として使用できるようになりました。
Tony O'Hagan

21

前述のようtoThrowに、テストで記述している関数であるため、関数に渡す必要があります。「この関数はxをスローすることを期待しています」

expect(() => parser.parse(raw))
  .toThrow(new Error('Parsing is not possible'));

使用している場合はジャスミン・マッチャを、彼らは状況に合わせたときにも、次のいずれかを使用することができます。

// I just want to know that an error was
// thrown and nothing more about it
expect(() => parser.parse(raw))
  .toThrowAnyError();

または

// I just want to know that an error of 
// a given type was thrown and nothing more
expect(() => parser.parse(raw))
  .toThrowErrorOfType(TypeError);

3
それはだexpect(foo).toThrowError(TypeError);ジャスミン2.5:jasmine.github.io/2.5/introduction
ベニー・ノイゲバウアー

9

私はそれがより多くのコードであることを知っていますが、あなたも行うことができます:

try
   do something
   @fail Error("should send a Exception")
 catch e
   expect(e.name).toBe "BLA_ERROR"
   expect(e.message).toBe 'Message'

私はこれに「自己文書化」の側面を好む傾向があります...エラー状態を単体テストしていることが非常に明白になります
JRulle

6

コーヒースクリプト愛好家のために

expect( => someMethodCall(arg1, arg2)).toThrow()

3

まだこの問題に直面している可能性のある人にとって、私にとって投稿された解決策は機能せず、このエラーをスローし続けました:エラーError: Expected function to throw an exception. をスローすることを期待していた関数は非同期関数であり、約束を期待していました拒否されてエラーがスローされます。これが私のコードで実行していたことです。

throw new Error('REQUEST ID NOT FOUND');

そしてそれは私が私のテストでやったことであり、それはうまくいきました:

it('Test should throw error if request not found', willResolve(() => {
         const promise = service.getRequestStatus('request-id');
                return expectToReject(promise).then((err) => {
                    expect(err.message).toEqual('REQUEST NOT FOUND');
                });
            }));

これをありがとう。私は非常に混乱しましたが、あなたのコメントは完全に理にかなっています。新しいexpectAsync jasmine.github.io/api/3.3/async-matchers.html
Benjamin
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.