Как написать тест, ожидающий ошибки в Жасмин?
Я пытаюсь написать тест для Jasmine Test Framework, который ожидает ошибку. В настоящий момент я использую интеграцию Jasmine Node.js от GitHub.
В моем модуле узла я имею следующий код:
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()
и некоторые другие варианты и просто не могу понять, как заставить его работать.
Ответы
Ответ 1
вы должны передать функцию в вызов 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"));
Ответ 2
Вы используете:
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");
Дуглас Крокфорд настоятельно рекомендует этот подход вместо использования «throw new Error ()» (способ прототипирования):
throw {
name: "Error",
message: "Parsing is not possible"
}
Ответ 3
Я заменяю Jasmine toThrow matcher следующим образом, которое позволяет вам сопоставлять свойство имени исключения или его свойство сообщения. Для меня это делает тесты более легкими для записи и менее хрупкими, поскольку я могу сделать следующее:
throw {
name: "NoActionProvided",
message: "Please specify an 'action' property when configuring the action map."
}
, а затем проверьте следующее:
expect (function () {
.. do something
}).toThrow ("NoActionProvided");
Это позволяет мне настроить сообщение об ошибке позже, не нарушая тестов, когда важно то, что он выбрал ожидаемый тип исключения.
Это замена forThrow, которая позволяет это:
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
Более элегантное решение, чем создание анонимной функции, единственной целью которой является обернуть другое, - это использовать 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
и, на мой взгляд, делает тест более читаемым. См. Также: fooobar.com/questions/19511/...
Ответ 5
Я знаю, что это больше кода, но вы также можете:
try
do something
@fail Error("should send a Exception")
catch e
expect(e.name).toBe "BLA_ERROR"
expect(e.message).toBe 'Message'
Ответ 6
Для любителей coffeescript
expect( => someMethodCall(arg1, arg2)).toThrow()
Ответ 7
Как уже упоминалось ранее, функция должна быть передана в 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);