你能编写期望throw的异步测试吗?

我正在写一个async测试,期望async函数抛出像这样:

it("expects to have failed", async () => {
let getBadResults = async () => {
await failingAsyncTest()
}
expect(await getBadResults()).toThrow()
})

但玩笑只是失败而不是通过测试:

 FAIL  src/failing-test.spec.js
● expects to have failed


Failed: I should fail!

如果我重写这个测试,看起来像这样:

expect(async () => {
await failingAsyncTest()
}).toThrow()

我得到这个错误,而不是通过测试:

expect(function).toThrow(undefined)


Expected the function to throw an error.
But it didn't throw anything.
112245 次浏览

你可以这样测试你的async函数:

it('should test async errors', async () =>  {
await expect(failingAsyncTest())
.rejects
.toThrow('I should fail');
});

'I should fail'字符串将匹配抛出的错误的任何部分。

我想在此基础上补充一点,说你正在测试的函数必须抛出一个实际的Error对象throw new Error(...)。如果你只是抛出一个像throw 'An error occurred!'这样的表达式,Jest似乎不能识别。

我一直在测试Firebase的云功能,这是我得出的结论:

test("It should test async on failing cloud functions calls", async () => {
await expect(async ()=> {
await failingCloudFunction(params)
})
.rejects
.toThrow("Invalid type"); // This is the value for my specific error
});

它构建在参杂的回答之上。

自定义错误类

rejects.toThrow的使用对你不起作用。相反,你可以结合rejects方法和toBeInstanceOf匹配器来匹配已经抛出的自定义错误。

例子

it("should test async errors", async () => {
await expect(asyncFunctionWithCustomError()).rejects.toBeInstanceOf(
CustomError
)
})
await expect(async () => {
await someAsyncFunction(someParams);
}).rejects.toThrowError("Some error message");

我们必须将代码包装在函数中以捕获错误。这里我们期望someAsyncFunction抛出的错误消息应该等于“一些错误消息”。我们也可以调用异常处理程序

await expect(async () => {
await someAsyncFunction(someParams);
}).rejects.toThrowError(new InvalidArgumentError("Some error message"));

阅读更多https://jestjs.io/docs/expect#tothrowerror

这对我很有效

it("expects to have failed", async () => {
let getBadResults = async () => {
await failingAsyncTest()
}
expect(getBadResults()).reject.toMatch('foo')
// or in my case
expect(getBadResults()).reject.toMatchObject({ message: 'foo' })
})

test("It should test async on failing cloud functions calls", async () => {
failingCloudFunction(params).catch(e => {
expect(e.message).toBe('Invalid type')
})
});

为了能够创建许多测试条件,而不必每次都解析承诺,这也可以工作:

it('throws an error when it is not possible to create an user', async () => {
const throwingFunction = () => createUser(createUserPayload)


// This is what prevents the test to succeed when the promise is resolved and not rejected
expect.assertions(3)


await throwingFunction().catch(error => {
expect(error).toBeInstanceOf(Error)
expect(error.message).toMatch(new RegExp('Could not create user'))
expect(error).toMatchObject({
details: new RegExp('Invalid payload provided'),
})
})
})

如果你想测试一个async函数不抛出:

it('async function does not throw', async () => {
await expect(hopefullyDoesntThrow()).resolves.not.toThrow();
});

不管返回的值是什么,上面的测试都将通过,即使是未定义的。

请记住,如果一个async函数抛出了一个错误,它实际上会在Node中作为承诺拒绝返回,而不是一个错误(这就是为什么如果你没有try/catch块,你会得到一个UnhandledPromiseRejectionWarning,与错误略有不同)。所以,就像其他人说的,这就是你使用either的原因:

  1. .rejects.resolves方法,或者a
  2. try/catch块在你的测试。
< p >参考: https://jestjs.io/docs/asynchronous#asyncawait < / p >

如果你想在测试用例中使用try/catch方法,你可以像下面这样做。

test("some test case name with success", async () => {
let response = null;
let failure = null;
// Before calling the method, make sure someAsyncFunction should be succeeded
try {
response = await someAsyncFunction();
} catch(err) {
error = err;
}
expect(response).toEqual(SOME_MOCK_RESPONSE)
expect(error).toBeNull();
})


test("some test case name with failure", async () => {
let response = null;
let error = null;
// Before calling the method, make sure someAsyncFunction should throw some error by mocking in proper way
try {
response = await someAsyncFunction();
} catch(err) {
error = err;
}
expect(response).toBeNull();
expect(error).toEqual(YOUR_MOCK_ERROR)
})