私はエラーを期待している Jasmine Test Framework のテストを書きます。現時点で私はGitHubからの Jasmine Node.js統合を使用しています 。
私のNodeモジュールには以下のコードがあります。
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()
と他のいくつかの変種も試してみましたが、どうやってそれを機能させるのか理解できません。
あなたは関数を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"));
あなたが使っている:
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"
}
JasmineのtoThrowマッチャーを次のように置き換えます。これにより、例外のnameプロパティまたはそのmessageプロパティを一致させることができます。私にとっては、次のようにするとテストの記述が簡単になり、脆弱性も少なくなります。
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;
};
唯一の目的が別のものをラップすることである無名関数を作成することよりももっと優雅な解決策は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
前述したように、関数はテストで記述している関数なので、toThrow
に渡す必要があります。「この関数はxをスローすると思います」
expect(() => parser.parse(raw))
.toThrow(new Error('Parsing is not possible'));
Jasmine-Matchers を使用している場合は、状況に合わせて次のいずれかを使用することもできます。
// 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);
私はそれがより多くのコードであることを知っていますが、あなたもすることができます:
try
do something
@fail Error("should send a Exception")
catch e
expect(e.name).toBe "BLA_ERROR"
expect(e.message).toBe 'Message'
コーヒー愛好家のために
expect( => someMethodCall(arg1, arg2)).toThrow()
まだこの問題に直面している可能性がある人のために、私にとって投稿された解決策はうまくいかず、このエラーを投げ続けました: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');
});
}));