我如何编写一个期望'错误'扔进茉莉花里?

我试图为茉莉测试框架编写一个测试,期望出现错误。目前我使用从GitHub集成Jasmine Node.js

在我的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()和其他一些变体,只是不知道如何使它工作。

281042 次浏览

您正在使用:

expect(fn).toThrow(e)

但是如果你看一下函数注释(expected is string):

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) {

我想你应该这样写(使用lambda - anonymous函数):

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

下面的例子证实了这一点:

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

道格拉斯Crockford强烈推荐这种方法,而不是使用&;throw new Error()&;(原型):

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

尝试使用匿名函数:

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

你应该传递一个函数到expect(...)调用中。你的错误代码:

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

实际上是尝试调用 parser.parse(raw),试图将结果传递给expect(...)

我用下面的代码替换了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;
};

对于CoffeeScript爱好者:

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

我知道这是更多的代码,但你也可以这样做:

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

比创建一个匿名函数(其唯一目的是包装另一个函数)更优雅的解决方案是使用ES5bind函数。绑定函数创建一个新函数,在调用该函数时,将其this关键字设置为所提供的值,并在调用新函数时所提供的任何参数之前设置给定的参数序列。

而不是:

# EYZ0

考虑:

# EYZ0

绑定语法允许您测试具有不同this值的函数,在我看来,这使测试更具可读性。参见:

Jasmine's toThrow匹配器是否要求参数被包装在匿名函数中?< / >

如前所述,需要将函数传递给toThrow,因为它是您在测试中描述的函数:“I expect this function to throw 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);

对我来说,发布的解决方案不起作用,它一直抛出这个错误:

错误:期望函数抛出异常。

我后来意识到,我期望抛出错误的函数是一个异步函数,并期望承诺被拒绝,然后抛出错误,这就是我在我的代码中所做的:

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');
});
}));

在我的例子中,抛出错误的函数是异步,所以我遵循:

await expectAsync(asyncFunction()).toBeRejected();
await expectAsync(asyncFunction()).toBeRejectedWithError(...);
it('it should fail', async () => {
expect.assertions(1);


try {
await testInstance.doSomething();
}
catch (ex) {
expect(ex).toBeInstanceOf(MyCustomError);
}
});