【问题标题】:How can I write a test which expects an 'Error' to be thrown in Jasmine?如何编写一个期望在 Jasmine 中抛出“错误”的测试?
【发布时间】:2011-05-07 21:05:06
【问题描述】:

我正在尝试为 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() 和其他一些变体,但不知道如何使它工作。

【问题讨论】:

标签: javascript testing node.js jasmine


【解决方案1】:
it('it should fail', async () => {
    expect.assertions(1);

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

【讨论】:

  • 解释一下。例如,想法/要点是什么?来自the Help Center“...总是解释为什么你提出的解决方案是合适的以及它是如何工作的”。请通过editing (changing) your answer 回复,而不是在 cmets 中(without "Edit:"、"Update:" 或类似的 - 答案应该看起来好像是今天写的)。
【解决方案2】:

在我的例子中,抛出错误的函数是async,所以我关注了this

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

【讨论】:

    【解决方案3】:

    对我来说,发布的解决方案不起作用,并且一直抛出此错误:

    错误:预期的函数会引发异常。

    我后来意识到我期望抛出错误的函数是一个 async 函数,并且期望 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');
            });
    }));
    

    【讨论】:

    【解决方案4】:

    比创建一个唯一目的是包装另一个匿名函数的更优雅的解决方案是使用ES5bind 函数。 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?

    【讨论】:

      【解决方案5】:

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

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

      【讨论】:

        【解决方案6】:

        CoffeeScript爱好者:

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

        【讨论】:

          【解决方案7】:

          您正在使用:

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

          【讨论】:

          • 实际上看代码 toThrow 会很高兴地接受一个异常对象/或/一个字符串。例如,查看它对 expected.message 的调用。
          • 它允许字符串作为没有消息属性的字符串的副作用
          • 如果您抛出一个对象而不是一个错误(如底部示例所示),那么您将不会在支持它的浏览器中获得堆栈跟踪。
          • @kybernetikos 令人惊讶,并不完全正确;如果您抛出非Error (jsfiddle.net/k1mxey8j),您仍然会在 Chrome 控制台中打印堆栈跟踪。但是,您抛出的对象当然不会有 .stack 属性,如果您想设置自动错误报告,这可能很重要。
          【解决方案8】:

          尝试使用匿名函数:

          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(parser.parse).toThrow(...)
          • 实用提示:您可以直接拨打expect(blah).toThrow()。没有参数意味着检查它是否抛出。不需要字符串匹配。另见:stackoverflow.com/a/9525172/1804678
          • 在我看来,包装匿名函数时测试的意图更明显。此外,它在所有测试中保持一致,例如,当您必须将参数传递给目标函数以使其抛出时。
          • @SubmittedDenied:这通常不起作用!如果parser.parse 使用this,在没有上下文的情况下传递它会产生意想不到的结果。你可以通过parser.parse.bind(parser),但老实说......匿名函数会更优雅。
          【解决方案9】:

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

          【讨论】:

          【解决方案10】:

          我将 Jasmine 的 toThrow 匹配器替换为以下内容,它允许您匹配异常的名称属性或其消息属性。对我来说,这使测试更容易编写并且不那么脆弱,因为我可以执行以下操作:

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

          【讨论】:

          • 真的应该将其作为自定义匹配器与现代 Jasmine 库一起实现。我做了类似的事情并创建了一个名为 toThrowErrorNamed 的自定义匹配器
          猜你喜欢
          • 2020-08-31
          • 2017-12-06
          • 1970-01-01
          • 2012-08-23
          • 1970-01-01
          • 2018-04-19
          • 2012-05-01
          • 2020-01-08
          • 1970-01-01
          相关资源
          最近更新 更多