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

时间:2010-11-10 12:57:40

标签: javascript testing node.js jasmine

我正在尝试为期望出错的Jasmine Test Framework编写测试。目前我正在使用Jasmine Node.js integration from GitHub

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

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()和其他一些变体,但却无法弄清楚如何使其发挥作用。

10 个答案:

答案 0 :(得分:735)

你应该将一个函数传递给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"));

答案 1 :(得分:63)

您正在使用:

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

道格拉斯·克罗克福德强烈推荐这种方法,而不是使用“抛出新的错误()”(原型方法):

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

答案 2 :(得分:22)

我用以下内容替换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;
};

答案 3 :(得分:21)

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

答案 4 :(得分:11)

如前所述,函数需要传递给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);

答案 5 :(得分:8)

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

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

答案 6 :(得分:5)

对于咖啡师爱好者

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

答案 7 :(得分:1)

对于仍然可能面临此问题的任何人,对我而言,发布的解决方案无法正常运行,并且不断抛出此错误:Error: Expected function to throw an exception. 我后来意识到,我期望抛出错误的函数是异步函数,并且期望被拒绝然后抛出错误,这就是我在代码中所做的事情:

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

答案 8 :(得分:1)

在我的情况下,函数抛出错误是异步的,因此我遵循了here

await expectAsync(asyncFunction()).toBeRejected();
await expectAsync(asyncFunction()).toBeRejectedWithError(...);

答案 9 :(得分:0)

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

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