如何在Jest中测试带回调的异步函数?相关实现与疑问
关于异步服务回调写法与Jest测试的问题解答
嘿,我来帮你一步步理清这些问题~
1. 这种回调写法算不算不良实践?
在现代JavaScript异步编程中,混合使用async函数和传统回调确实属于不够优雅的写法,原因主要有这几点:
- async函数本身的设计就是为了让异步代码更像同步代码,而回调会打破这种简洁性,后续扩展容易引入嵌套逻辑;
- 回调风格的错误处理分散在不同的回调参数里,不如Promise的
try/catch或者.then/.catch统一直观; - 不符合当前社区的主流异步编程习惯,团队协作时会增加理解和维护成本。
这算不上“严重错误”,但确实是值得优化的地方。
2. 应该改成返回Promise吗?
非常推荐改成返回Promise的写法,这样能和async函数的特性完美契合,代码可读性和可维护性都会提升不少。
修改后的示例代码:
const MyService = { async stringify(entry) { try { const response = await axios.post('localhost:3005/stringify', { entry }) return response.data } catch (minificationError) { if (minificationError.response.status === 500) { throw new Error('error 1') } else { throw new Error('error 2') } } } }
在组件中调用时,就可以用更清晰的方式处理:
async function handleStringify(entry) { try { const result = await MyService.stringify(entry) // 处理成功逻辑 } catch (err) { if (err.message === 'error 1') { // 处理500错误场景 } else { // 处理其他错误场景 } } }
3. Jest中如何mock状态码测试失败场景?
不管是回调版本还是Promise版本,核心都是mock axios.post 的返回值,让它抛出带有指定状态码的错误。
针对你的回调版本测试:
首先在测试文件顶部mock axios:
jest.mock('axios')
然后编写测试用例,模拟不同状态码的错误:
describe('MyService.stringify', () => { it('should call callback with "error 1" when response status is 500', async () => { // 模拟axios.post抛出500错误 axios.post.mockRejectedValue({ response: { status: 500 } }) // 创建mock回调函数 const mockCb = jest.fn() await MyService.stringify('test entry', mockCb) // 验证回调被正确调用 expect(mockCb).toHaveBeenCalledWith('error 1', null) }) it('should call callback with "error 2" when response status is not 500', async () => { axios.post.mockRejectedValue({ response: { status: 400 } // 用400状态码模拟其他错误 }) const mockCb = jest.fn() await MyService.stringify('test entry', mockCb) expect(mockCb).toHaveBeenCalledWith('error 2', null) }) it('should call callback with data on success', async () => { axios.post.mockResolvedValue({ data: { some: 'value' } }) const mockCb = jest.fn() await MyService.stringify('test entry', mockCb) expect(mockCb).toHaveBeenCalledWith(null, { some: 'value' }) }) })
针对Promise版本的测试(更简洁):
describe('MyService.stringify', () => { it('should throw "error 1" when response status is 500', async () => { axios.post.mockRejectedValue({ response: { status: 500 } }) await expect(MyService.stringify('test entry')).rejects.toThrow('error 1') }) it('should return data on success', async () => { axios.post.mockResolvedValue({ data: { some: 'value' } }) const result = await MyService.stringify('test entry') expect(result).toEqual({ some: 'value' }) }) })
内容的提问来源于stack exchange,提问作者McDerp
相关产品推荐
相关产品推荐

