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

时间:2017-09-04 18:43:04

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

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

14 个答案:

答案 0 :(得分:79)

在Jest中你必须将一个函数传递给expect(function).toThrow(空格或错误类型)。

示例:

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

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

示例:

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

答案 1 :(得分:26)

有点奇怪,但作品和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");
  }
});

Catch阻止了您的异常,然后您可以对您的已提升的Error进行测试。如果预期expect(true).toBe(false);不会被抛出,则需要使用奇怪的Error来使测试失败。否则,此行永远不可访问(应在它们之前引发Error)。

答案 2 :(得分:16)

从我(尽管有限制)接触Jest的过程中,我发现expect().toThrow()适用于只想测试特定消息引发错误的情况:

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

或者抛出特定类型的错误:

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

如果您同时尝试这两种方法,则会得到假阳性。例如,如果您的代码抛出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!');
        }
    }); 
});

如果functionUnderTest()没有引发错误,则将命中断言,但是expect.assertions(2)将失败并且测试将失败。

答案 3 :(得分:9)

如果您使用的是Promise

await expect(Promise.reject(new HttpException('Error message', 402)))
  .rejects.toThrowError(HttpException);

答案 4 :(得分:7)

Haven自己尝试过,但我建议使用Jest的toThrow断言。所以我想你的例子看起来像这样:

/etc/init.d/celerybeat

再一次,没有测试它,但我认为它应该有效。

如果这有帮助,请告诉我。

快乐的编码!

答案 5 :(得分:7)

Jest有一个方法expect(t).toThrowError(TypeError); 来测试一个函数在被调用时抛出。

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

 if ((myrow>-1)&(mycol>-1)&(myrow<nprow)&(mycol<npcol)) {
    // do the job
    Cblacs_gridexit( 0 );
 }

The docs

答案 6 :(得分:5)

Peter Danis' post之前,我只想强调他的解决方案的一部分,其中涉及“将一个函数[传递]到Expect(function).toThrow(空白或错误​​类型)”。

在Jest中,当您测试应该抛出错误的情况时,在被测函数的Expect()包装内,您需要提供一个附加的箭头函数包装层以使其起作用。即

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

expect(functionUnderTesting();).toThrow(ErrorTypeOrErrorMessage);

右:

expect(() => { functionUnderTesting(); }).toThrow(ErrorTypeOrErrorMessage);

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

答案 7 :(得分:2)

现代玩笑使您可以对拒绝的值进行更多检查。例如:

const request = Promise.reject({statusCode: 404})
await expect(request).rejects.toMatchObject({ statusCode: 500 });

将失败,并显示错误

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

- Expected
+ Received

  Object {
-   "statusCode": 500,
+   "statusCode": 404,
  }

答案 8 :(得分:2)

documentation清楚地说明了如何执行此操作。假设我有一个带有两个参数的函数,如果其中一个参数为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

您的测试

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()
  })
})

答案 9 :(得分:1)

查看 toThrow 方法。

您必须将代码包装在额外的函数回调中!

您应该同时检查:错误消息及其类型。

例如:

expect(
  () => { // additional function wrap
    yourCodeToTest();
  }
).toThrow(
  new RangeError('duplicate prevArray value: A')
);

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

您应该始终检查错误消息,以确保您检查的是正确的 throw 情况,并且不会收到您的代码可能 throw 的另一个错误。

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

答案 10 :(得分:0)

尝试
expect(t).rejects.toThrow()

答案 11 :(得分:0)

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

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

答案 12 :(得分:0)

我最终为我们的test-utils库编写了一种便捷方法

/**
 *  Utility method to test for a specific error class and message in Jest
 * @param {fn, expectedErrorClass, expectedErrorMessage }
 * @example   failTest({
      fn: () => {
        return new MyObject({
          param: 'stuff'
        })
      },
      expectedErrorClass: MyError,
      expectedErrorMessage: 'stuff not yet implemented'
    })
 */
  failTest: ({ fn, expectedErrorClass, expectedErrorMessage }) => {
    try {
      fn()
      expect(true).toBeFalsy()
    } catch (err) {
      let isExpectedErr = err instanceof expectedErrorClass
      expect(isExpectedErr).toBeTruthy()
      expect(err.message).toBe(expectedErrorMessage)
    }
  }

答案 13 :(得分:0)

我设法结合了一些答案并最终得到了这个:

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