如何在Jest中测试异步函数不抛出错误
我完全理解你的困惑——Jest的异步断言逻辑确实和Jasmine有些不一样,尤其是当你想验证异步函数不会抛出错误的时候。
先解释你原来的写法为什么会失败:
你用了await expect(() => execute(1, 1)).rejects.not.toThrow(),这里的rejects已经在断言「这个promise一定会被拒绝」,所以当execute成功resolve时,rejects本身就会触发失败,后面的not.toThrow()根本没机会生效,这就是你看到"Received promise resolved instead of rejected"错误的原因。
下面给你两种正确的实现方式:
方式一:最简单直接的写法
如果你的需求只是验证execute执行时不会抛出错误(即能成功resolve),其实不需要复杂的断言——直接await这个函数即可:
test('execute does not throw an error', async () => { await execute(1, 1); });
原理很简单:如果execute抛出错误(或者reject),await会把这个错误抛出,Jest会自动捕获并标记测试失败;如果函数成功resolve,测试就会顺利通过。
方式二:用Jest的异步断言明确验证
如果你想用更明确的断言形式(让测试意图更清晰),可以用resolves而不是rejects:
test('execute resolves successfully without errors', async () => { // 如果你不关心返回值,仅验证无错误抛出 await expect(execute(1, 1)).resolves.not.toThrow(); // 或者如果你只关心它能成功resolve,也可以写: await expect(execute(1, 1)).resolves.toBeDefined(); });
这里resolves会断言promise成功resolve,只要execute没有reject,这个断言就会通过;如果execute抛出错误,resolves会直接失败,完全符合你的测试预期。
另外还有一种兼容同步/异步错误的写法,适合需要覆盖「同步参数校验错误」+「异步执行错误」的场景:
test('execute does not throw any errors', async () => { await expect(async () => { await execute(1, 1); }).not.toThrow(); });
这种写法会捕获函数内部所有同步抛出的错误和异步reject的错误,确保测试覆盖更全面。
总结一下:Jest的rejects是专门用来断言promise会被拒绝的,当你要验证promise不会被拒绝时,应该用resolves或者直接等待函数执行,而不是反过来用rejects.not.toThrow()。
内容的提问来源于stack exchange,提问作者jaucourt

