You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.09 15:02:55