如何编写一个期望在Jasmine中抛出Error的测试?

ech*_*hox 457 javascript testing node.js jasmine

我正在尝试为Jasmine测试框架编写测试,该测试期望出现错误.目前我正在使用GitHubJasmine Node.js集成.

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

throw new Error("Parsing is not possible");
Run Code Online (Sandbox Code Playgroud)

现在我尝试编写一个期望这个错误的测试:

describe('my suite...', function() {
    [..]
    it('should not parse foo', function() {
    [..]
        expect(parser.parse(raw)).toThrow(new Error("Parsing is not possible"));
    });
});
Run Code Online (Sandbox Code Playgroud)

我也试过了Error()一些其他的变种,只是无法弄清楚如何使它工作.

Pet*_*son 771

你应该将一个函数传递给这个expect(...)电话.你在这里的代码:

// incorrect:
expect(parser.parse(raw)).toThrow(new Error("Parsing is not possible"));
Run Code Online (Sandbox Code Playgroud)

试图以实际调用 parser.parse(raw),企图将结果传递到expect(...),

请尝试使用匿名函数:

expect( function(){ parser.parse(raw); } ).toThrow(new Error("Parsing is not possible"));
Run Code Online (Sandbox Code Playgroud)

  • 有用的提示:你可以简单地调用`expect(blah).toThrow()`.没有参数意味着检查它是否会抛出.不需要字符串匹配.另见:http://stackoverflow.com/a/9525172/1804678 (58认同)
  • 如果你也不需要传递参数,你也可以将函数传递给expect:`expect(parser.parse).toThrow(...)` (28认同)
  • @SubmittedDenied:这一般不起作用!如果`parser.parse`使用`this`,那么在没有上下文的情况下传递它将产生意外的结果.你可以传递`parser.parse.bind(parser)`,但老实说......一个匿名函数会更优雅. (9认同)
  • 在我看来,当包装在匿名函数中时,测试的意图更加明显。此外,它在所有测试中保持一致,例如,当您必须将参数传递给目标函数以使其抛出异常时。 (2认同)
  • @LanceKind抱歉,necro,但是,您必须传递一个函数的原因是,将对值进行评估并在将其传递到期望值之前引发异常。 (2认同)

And*_*iwa 66

您正在使用:

expect(fn).toThrow(e)
Run Code Online (Sandbox Code Playgroud)

但是如果你看一下函数注释(期望是字符串):

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) {
Run Code Online (Sandbox Code Playgroud)

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

expect(function() { parser.parse(raw); } ).toThrow("Parsing is not possible");
Run Code Online (Sandbox Code Playgroud)

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

expect(function () {throw new Error("Parsing is not possible")}).toThrow("Parsing is not possible");
Run Code Online (Sandbox Code Playgroud)

Douglas Crockford强烈推荐这种方法,而不是使用"throw new Error()"(原型方法):

throw {
   name: "Error",
   message: "Parsing is not possible"
}
Run Code Online (Sandbox Code Playgroud)

  • 如果您抛出一个对象而不是一个错误(如在底部的示例中那样),那么您将无法在支持它的浏览器中获得堆栈跟踪. (16认同)
  • 实际上查看代码toThrow会愉快地采用异常对象/或/字符串.例如,查看它对expected.message进行的调用. (3认同)
  • @kybernetikos令人惊讶,并非完全正确; 如果您抛出非"错误"(http://jsfiddle.net/k1mxey8j/),您仍然会在Chrome控制台中打印堆栈跟踪.但是,抛出的对象当然不会有`.stack`属性,如果你想设置*自动*错误报告,这可能很重要. (2认同)

Jak*_*ake 23

我用以下代码替换Jasmine的toThrow匹配器,它允许您匹配异常的name属性或其message属性.对我来说,这使得测试更容易编写并且更不易碎,因为我可以执行以下操作:

throw {
   name: "NoActionProvided",
   message: "Please specify an 'action' property when configuring the action map."
}
Run Code Online (Sandbox Code Playgroud)

然后用以下测试:

expect (function () {
   .. do something
}).toThrow ("NoActionProvided");
Run Code Online (Sandbox Code Playgroud)

这让我可以在不破坏测试的情况下稍后调整异常消息,重要的是它抛出了预期的异常类型.

这是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;
};
Run Code Online (Sandbox Code Playgroud)

  • 谢谢Jess - 这是真的,但是它可能会抛出一些其他错误,比如TypeError,我的测试会错误地传递,掩盖一个真正的错误. (5认同)
  • 一个很好的方法,但{name:'...',message:'...'}是JavaScript中的一个正确的Error对象? (4认同)
  • @Jake!我找到了更好的方法!!!! 你可以简单地调用`expect(blah).toThrow()`.没有参数意味着检查它是否会抛出.不需要字符串匹配.另见:http://stackoverflow.com/a/9525172/1804678 (4认同)
  • 您现在也可以使用RegEx作为toThrow()的参数. (4认同)

Jon*_*ych 23

比创建匿名函数更优雅的解决方案是使用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


Jam*_*son 17

如前所述,函数需要传递给toThrow你在测试中描述的函数:"我希望这个函数抛出x"

expect(() => parser.parse(raw))
  .toThrow(new Error('Parsing is not possible'));
Run Code Online (Sandbox Code Playgroud)

如果使用Jasmine-Matchers,您也可以根据情况使用以下其中一种;

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

要么

// I just want to know that an error of 
// a given type was thrown and nothing more
expect(() => parser.parse(raw))
  .toThrowErrorOfType(TypeError);
Run Code Online (Sandbox Code Playgroud)

  • 它是`expect(foo).toThrowError(TypeError);`在Jasmine 2.5中:https://jasmine.github.io/2.5/introduction (3认同)

Wil*_*mer 10

就我而言,抛出错误的函数是async,所以我遵循以下操作

await expectAsync(asyncFunction()).toBeRejected();
await expectAsync(asyncFunction()).toBeRejectedWithError(...);
Run Code Online (Sandbox Code Playgroud)


tol*_*ard 9

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

try
   do something
   @fail Error("should send a Exception")
 catch e
   expect(e.name).toBe "BLA_ERROR"
   expect(e.message).toBe 'Message'
Run Code Online (Sandbox Code Playgroud)


fer*_*hur 6

对于coffeescript爱好者

expect( => someMethodCall(arg1, arg2)).toThrow()
Run Code Online (Sandbox Code Playgroud)


jcr*_*ada 5

it('it should fail', async () => {
    expect.assertions(1);

    try {
        await testInstance.doSomething();
    }
    catch (ex) {
        expect(ex).toBeInstanceOf(MyCustomError);
    }
});
Run Code Online (Sandbox Code Playgroud)