如何在Jest中测试抛出异常的类型

Tra*_*ron 78 javascript unit-testing jestjs

我正在使用一些代码,我需要测试函数抛出的异常类型(是TypeError,ReferenceError等).

我目前的测试框架是AVA,我可以测试它作为第二个参数t.throws方法,就像这里:

it('should throw Error with message \'UNKNOWN ERROR\' when no params were passed', (t) => {
  const error = t.throws(() => {
    throwError();
  }, TypeError);

  t.is(error.message, 'UNKNOWN ERROR');
});
Run Code Online (Sandbox Code Playgroud)

我开始将我的测试改写为Jest,但却找不到如何轻松地做到这一点.它甚至可能吗?

Pet*_*nis 114

在Jest中,您必须将函数传递给expect(函数).toThrow(空白或错误​​类型).

例:

test("Test description", () => {
  const t = () => {
    throw new TypeError();
  };
  expect(t).toThrow(TypeError);
});
Run Code Online (Sandbox Code Playgroud)

如果你需要测试一个现有函数是否抛出一组参数,你必须将它包装在expect()中的匿名函数中.

例:

test("Test description", () => {
  expect(() => {http.get(yourUrl, yourCallbackFn)}).toThrow(TypeError);
});
Run Code Online (Sandbox Code Playgroud)

  • @GerasimosRagavanis,当你测试异步函数时,你应该 `await Expect(yourAsyncFn(...)).rejects.toThrow(...)`,就像 Douglas Caina [此处](https://stackoverflow.com) 所回答的那样/a/68557059/2099911)。 (47认同)
  • @rags2riches 需要匿名函数,因为“expect(x).toThrow()”要求“x”是对抛出函数的引用。如果您改为传递“expect(x()).toThrow()”,JavaScript 将解析“x()”,这可能会立即导致错误,并且很可能导致测试失败。 (14认同)
  • 好 - 我可以问为什么需要匿名函数包装器吗?有了包装器它就可以工作,但没有它就不行了。 (4认同)

Dou*_*ina 74

我设法结合一些答案并最终得到以下结果:

it('should throw', async () => {
    await expect(service.methodName('some@email.com', 'unknown')).rejects.toThrow(
      HttpException,
    );
  });
Run Code Online (Sandbox Code Playgroud)

  • 你在这里提到的小细节让我省了很多麻烦:“await”语句应该在“expect”的**外部**,而不是内部。谢谢! (6认同)

bod*_*sog 46

有点奇怪,但作品和imho可读性很好:

it('should throw Error with message \'UNKNOWN ERROR\' when no params were passed', () => {
  try {
      throwError();
      // Fail test if above expression doesn't throw anything.
      expect(true).toBe(false);
  } catch (e) {
      expect(e.message).toBe("UNKNOWN ERROR");
  }
});
Run Code Online (Sandbox Code Playgroud)

Catch阻止你的异常,然后你可以测试你的凸起Error.expect(true).toBe(false);如果预期Error不会被抛出,则需要奇怪的是你的测试失败.否则,此行永远不可访问(Error应在它们之前引发).

  • 当Jest已经有expect.toThrow()检查异常的方式时,这是一种非常详细的异常测试方法:http://jestjs.io/docs/en/expect.html#tothrowerror (9认同)
  • @Valery 或:莎士比亚风格的`expect('to be').not.toBe('to be')`。 (5认同)
  • 你不需要做出一个假断言来失败 - 你可以简单地使用 `fail(...)` :) (4认同)
  • 是的,但是它仅测试类型,而不测试消息或其他内容,问题是关于测试消息,而不是类型。 (3认同)
  • 哈哈 确实像这样,因为我的代码需要测试抛出的错误的值,所以我需要实例。我会写像`expect('here')。not.toBe('here');`这样的错误期望只是为了好玩:-) (2认同)
  • 最被低估的答案! (2认同)

Igo*_*rev 24

查看toThrow方法。

您必须将代码包装在附加函数回调中!

您应该检查以下两项:错误消息及其类型。

例如:

// additional function wrap
const wrap = () => {
  yourCodeToTest();
};

// test error message
expect(wrap).toThrow('UNKNOWN ERROR');

// test error type
expect(wrap).toThrow(TypeError);
Run Code Online (Sandbox Code Playgroud)

由于额外的回调包装,代码不会立即运行,因此jest将能够捕获它。

您应该始终检查错误消息,以确保您检查的throw大小写正确,并且不会出现代码可能出现的另一个错误throw

检查错误类型也很好,因此客户端代码可以依赖它。


小智 21

有一种方法可以等待来自异步函数的错误,您只需编写代码,如下例所示

await expect(yourAsyncFunction()).rejects.toThrowError();
Run Code Online (Sandbox Code Playgroud)


Sla*_*nov 19

Modern Jest 允许您对被拒绝的值进行更多检查。例如:

const request = Promise.reject({statusCode: 404})
await expect(request).rejects.toMatchObject({ statusCode: 500 });
Run Code Online (Sandbox Code Playgroud)

会因错误而失败

Error: expect(received).rejects.toMatchObject(expected)

- Expected
+ Received

  Object {
-   "statusCode": 500,
+   "statusCode": 404,
  }
Run Code Online (Sandbox Code Playgroud)


Saf*_*hab 18

您必须将所需函数的代码包装在另一个箭头函数中,否则错误将不会被捕获并且断言将失败。

您要测试的功能:

const testThrowingError = () => {
    throw new Error();
  };
Run Code Online (Sandbox Code Playgroud)

考试:

describe("error function should Throw Error", () => {
  expect(() =>testThrowingError()).toThrowError();
});
Run Code Online (Sandbox Code Playgroud)

资源: https: //jestjs.io/docs/expect#tothrowerror


Tal*_*ffe 17

我使用一个更简洁的版本:

expect(() => {
  //code block that should throw error
}).toThrow(TypeError) //or .toThrow('expectedErrorMessage')
Run Code Online (Sandbox Code Playgroud)

  • 简短而精确。 (11认同)

Žel*_*vić 14

如果您正在使用Promises:

await expect(Promise.reject(new HttpException('Error message', 402)))
  .rejects.toThrowError(HttpException);
Run Code Online (Sandbox Code Playgroud)


小智 12

Peter Danis 的帖子之后,我只想强调他的解决方案中涉及“[将] 函数传入 expect(function).toThrow(blank or type of error)”的部分。

在 Jest 中,当您测试应该抛出错误的情况时,在被测函数的 expect() 包装中,您需要提供一个额外的箭头函数包装层以使其工作。IE

错误(但大多数人的逻辑方法):

expect(functionUnderTesting();).toThrow(ErrorTypeOrErrorMessage);
Run Code Online (Sandbox Code Playgroud)

对:

expect(() => { functionUnderTesting(); }).toThrow(ErrorTypeOrErrorMessage);
Run Code Online (Sandbox Code Playgroud)

这很奇怪,但它应该使测试运行成功。

  • 感谢你的回答。令人难以置信的是,Jest 的文档隐藏了有关功能的重要信息,从而使事情变得困难。 (2认同)

Liu*_*tao 12

我已经成功地使用了这个

await expect(
      async () => await apiCalls()
    ).rejects.toThrow();
Run Code Online (Sandbox Code Playgroud)


And*_*CIO 10

我自己还没有尝试过,但我建议使用Jest的toThrow断言。因此,我想您的示例将如下所示:

it('should throw Error with message \'UNKNOWN ERROR\' when no params were passed', (t) => {
  const error = t.throws(() => {
    throwError();
  }, TypeError);

  expect(t).toThrowError('UNKNOWN ERROR');
  //or
  expect(t).toThrowError(TypeError);
});
Run Code Online (Sandbox Code Playgroud)

再次,没有测试它,但我认为它应该工作。

让我知道是否有帮助。

编码愉快!


小智 10

从我(虽然有限)接触Jest的过程中,我发现expect().toThrow()如果只想测试一条特定消息引发的错误,这是合适的:

expect(() => functionUnderTest()).toThrow(TypeError);

或抛出特定类型的错误:

expect(() => functionUnderTest()).toThrow('Something bad happened!');

如果您尝试同时执行这两项操作,则会得到误报。例如,如果您的代码throw RangeError('Something bad happened!'),则此测试将通过:

expect(() => functionUnderTest()).toThrow(new TypeError('Something bad happened!'));

bodolsog的答案表明使用try / catch的答案很接近,但是与其期望true为假以确保catch中的期望断言被击中,还可以expect.assertions(2)在测试开始时使用2期望断言的数量。我觉得这更准确地描述了测试的意图。

测试错误的类型和消息的完整示例:

describe('functionUnderTest', () => {
    it('should throw a specific type of error.', () => {
        expect.assertions(2);

        try {
            functionUnderTest();
        } catch (error) {
            expect(error).toBeInstanceOf(TypeError);
            expect(error).toHaveProperty('message', 'Something bad happened!');
        }
    }); 
});
Run Code Online (Sandbox Code Playgroud)

如果functionUnderTest()不抛出错误,则声明将被命中,但expect.assertions(2)将失败并且测试将失败。

  • 当测试在“catch”之外没有任何断言时,“expect.hasAssertions()”可能是更好的选择,因为如果添加/删除断言,则不必更新数字。 (3认同)

ale*_*mac 8

Jest有一个方法toThrow(error)来测试一个函数在被调用时抛出.

所以,在你的情况下你应该这样称呼它:

expect(t).toThrowError(TypeError);
Run Code Online (Sandbox Code Playgroud)

文档


Ikr*_*ula 7

Jest 版本:29
您有一个异步函数,需要测试是否抛出错误。

await expect(listener.onMessage(data, msg)).rejects.toThrow();
Run Code Online (Sandbox Code Playgroud)

断言准确的错误消息:

await expect(listener.onMessage(data, msg)).rejects.toThrow("Data not found!");
Run Code Online (Sandbox Code Playgroud)


Gil*_*ert 6

文档清楚地说明了如何执行此操作。假设我有一个带有两个参数的函数,如果其中一个是null.

function concatStr(str1, str2) {
  const isStr1 = str1 === null
  const isStr2 = str2 === null
  if(isStr1 || isStr2) {
    throw "Parameters can't be null"
  }
  ... // Continue your code
Run Code Online (Sandbox Code Playgroud)

你的测试

describe("errors", () => {
  it("should error if any is null", () => {
    // Notice that the expect has a function that returns the function under test
    expect(() => concatStr(null, "test")).toThrow()
  })
})
Run Code Online (Sandbox Code Playgroud)


Yas*_*obi 5

还有一种更简单的方法来针对错误消息进行断言。此方法的优点在于您不需要重建错误对象或拥有完整的错误消息。只要您的错误包含错误消息的一部分,我们就可以假设它是正确的类型。IE

 const printOnlyString = (str) => {
   if(typeof str !== "string"){
     throw Error("I can only print strings ${typeof str) given");
   }
   else {
     console.log(str);
   } 
 }

Run Code Online (Sandbox Code Playgroud)
expect(() => printOnlyString(123)).toThrow(/can only print strings/)
Run Code Online (Sandbox Code Playgroud)