我正在尝试为 Jasmine Test Framework 编写一个预期错误的测试。目前我正在使用 Jasmine Node.js integration from GitHub。
在我的 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()
和其他一些变体,但不知道如何使其工作。
Function.bind
:stackoverflow.com/a/13233194/294855
尝试使用匿名函数:
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(...)
,
您正在使用:
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) {
我想你可能应该这样写(使用 lambda - 匿名函数):
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"
}
Error
(jsfiddle.net/k1mxey8j),您仍然会在 Chrome 控制台中打印堆栈跟踪。但是,您的抛出对象当然没有 .stack
属性,如果您想设置 自动 错误报告,这可能很重要。
如前所述,需要将一个函数传递给 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);
expect(foo).toThrowError(TypeError);
:jasmine.github.io/2.5/introduction
比创建一个唯一目的是包装另一个匿名函数的更优雅的解决方案是使用 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");
bind 语法允许您测试具有不同 this
值的函数,并且在我看来使测试更具可读性。也可以看看:
Does Jasmine's toThrow matcher require the argument to be wrapped in an anonymous function?
我将 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;
};
我知道那是更多的代码,但你也可以这样做:
try
Do something
@fail Error("should send a Exception")
catch e
expect(e.name).toBe "BLA_ERROR"
expect(e.message).toBe 'Message'
在我的例子中,抛出错误的函数是 async,所以我遵循 this:
await expectAsync(asyncFunction()).toBeRejected();
await expectAsync(asyncFunction()).toBeRejectedWithError(...);
对我来说,发布的解决方案不起作用,它一直抛出这个错误:
错误:预期函数会引发异常。
后来我意识到我期望抛出错误的函数是一个异步函数,并且期望 promise 被拒绝然后抛出错误,这就是我在代码中所做的:
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 解决了这个问题
it('it should fail', async () => {
expect.assertions(1);
try {
await testInstance.doSomething();
}
catch (ex) {
expect(ex).toBeInstanceOf(MyCustomError);
}
});
expect(parser.parse).toThrow(...)
expect(blah).toThrow()
。没有参数意味着检查它是否抛出。不需要字符串匹配。另请参阅:stackoverflow.com/a/9525172/1804678parser.parse
使用this
,则在没有上下文的情况下传递它会产生意想不到的结果。你可以通过parser.parse.bind(parser)
,但老实说......匿名函数会更优雅。