Javascript 如何编写预期Jasmine中会抛出错误的测试?

Javascript 如何编写预期Jasmine中会抛出错误的测试?,javascript,testing,node.js,jasmine,Javascript,Testing,Node.js,Jasmine,我正在尝试为编写一个测试,该测试预期会出错。目前,我正在使用一个 在我的节点模块中,我有以下代码: throw new Error("Parsing is not possible"); 现在我尝试编写一个测试,该测试预计会出现以下错误: describe('my suite...', function() { [..] it('should not parse foo', function() { [..] expect(parser.parse(ra

我正在尝试为编写一个测试,该测试预期会出错。目前,我正在使用一个

在我的节点模块中,我有以下代码:

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(fn).toThrow(e)
但是如果您要查看函数注释(预期为字符串):

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

这在以下示例中得到确认:

expect(function () {throw new Error("Parsing is not possible")}).toThrow("Parsing is not possible");
Douglas Crockford强烈推荐这种方法,而不是使用“抛出新错误()”(原型法):


请尝试改用匿名函数:

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"));

正在尝试调用解析器。parse(raw)试图将结果传递到
expect(…)

我将Jasmine的toThrow matcher替换为以下内容,它允许您匹配异常的name属性或其message属性。对我来说,这使测试更容易编写,也不那么脆弱,因为我可以做到以下几点:

throw {
   name: "NoActionProvided",
   message: "Please specify an 'action' property when configuring the action map."
}
expect (function () {
   .. do something
}).toThrow ("NoActionProvided");
然后进行以下测试:

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

咖啡爱好者

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'

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

而不是:

expect(函数(){parser.parse(raw,config);}).toThrow(“解析不可能”)

考虑:

expect(parser.parse.bind(parser,raw,config)).toThrow(“解析不可能”)


bind语法允许您使用不同的
this
值测试函数,在我看来,它使测试更具可读性。另请参见:

如前所述,需要将函数传递给
toThrow
,因为它是您在测试中描述的函数:“我希望此函数抛出x”

如果使用,您还可以在适合的情况下使用以下选项之一:

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


对于仍然可能面临此问题的任何人,对我来说,发布的解决方案不起作用,它不断抛出此错误:
error:预期函数将抛出异常。
后来我意识到,我希望抛出错误的函数是一个异步函数,希望承诺被拒绝,然后抛出错误,这就是我在代码中所做的:

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

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


实际上,查看下面的代码会很高兴地得到一个异常对象/或一个字符串。检查它对expected.message的调用。例如,它允许字符串作为没有消息属性的字符串的副作用。如果您抛出一个对象而不是一个错误(如下面的示例所示),那么您在支持它的浏览器中就不会得到堆栈跟踪。@kybernetikos,令人惊讶的是,不完全正确;如果抛出一个非
错误
(),您仍然会在Chrome控制台中得到一个堆栈跟踪。但是,您抛出的对象当然没有
.stack
属性,如果您想设置自动错误报告,这可能很重要。如果您不需要传递参数,也可以传递函数expect:
expect(parser.parse)。toThrow(…)
帮助提示:您可以简单地调用
expect(blah).toThrow()
。“无参数”意味着检查它是否抛出。不需要字符串匹配。另请参见:在我看来,当包装在匿名函数中时,测试的意图更为明显。此外,当您必须向目标函数传递参数以使其抛出时,它在所有测试中保持一致。@submitteded:这通常不起作用!如果
parser.parse
使用
this
,则在没有上下文的情况下传递它将产生意外的结果。您可以传递
parser.parse.bind(parser)
,但老实说。。。匿名函数会更优雅。若要向正在测试的函数传递参数,而不使用匿名函数,请尝试
function.bind
:它是
expect(foo).tothroweror(TypeError)谢谢。我很困惑,但你的评论很有道理。我使用新的
expectAsync
// 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(...);