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

如何使用Jest模拟Promise化的child_process exec方法

问题分析与解决方案

你的测试超时是因为util.promisify依赖回调风格的函数实现Promise转换,但你当前mock的exec直接返回普通对象,导致promisify生成的Promise永远无法resolve或reject,测试一直等待直到超时。另外测试代码里还有个笔误:expected(result).toEqual(expected)应该改成expect(result).toEqual(expected)。

下面是两种正确的模拟方式:

方式一:模拟child_process.exec的回调行为(推荐)

这种方式更贴近真实逻辑,因为promisify本质是把(err, stdout, stderr)风格的回调转成Promise:

const { Command } = require('../src/utils')

// Mock node:child_process的exec方法,模拟回调逻辑
jest.mock('node:child_process', () => ({
  exec: jest.fn()
}))

describe('Command', () => {
  it('执行命令成功时返回正确结果', async () => {
    const mockExec = require('node:child_process').exec
    // 模拟成功场景:调用回调时传入null(无错误)和输出内容
    mockExec.mockImplementation((cmd, callback) => {
      callback(null, '目录列表内容', '')
    })

    const command = new Command()
    const result = await command.execute('ls -la')

    expect(result).toEqual({
      code: 0,
      stdout: '目录列表内容',
      stderr: ''
    })
    // 验证exec被正确调用
    expect(mockExec).toHaveBeenCalledWith('ls -la', expect.any(Function))
  })

  it('命令执行失败时返回错误信息', async () => {
    const mockExec = require('node:child_process').exec
    // 模拟失败场景:回调传入错误对象,包含错误码、部分输出和错误信息
    mockExec.mockImplementation((cmd, callback) => {
      callback({
        code: 2,
        stdout: '部分输出内容',
        stderr: '找不到该命令'
      })
    })

    const command = new Command()
    const result = await command.execute('invalid-command')

    expect(result).toEqual({
      code: 2,
      stdout: '部分输出内容',
      stderr: '找不到该命令'
    })
  })
})

方式二:直接Mockutil.promisify的返回

如果你不需要测试promisify的调用细节,可以直接让它返回一个模拟的Promise版本exec:

const { Command } = require('../src/utils')
const util = require('node:util')

// Mock util.promisify,让它返回我们自定义的Promise函数
jest.mock('node:util', () => ({
  promisify: jest.fn(() => {
    return (cmd) => Promise.resolve({ stdout: '测试输出', stderr: '' })
  })
}))

describe('Command', () => {
  it('执行命令成功返回结果', async () => {
    const command = new Command()
    const result = await command.execute('ls -la')

    expect(result).toEqual({
      code: 0,
      stdout: '测试输出',
      stderr: ''
    })
    // 验证promisify被调用过
    expect(util.promisify).toHaveBeenCalled()
  })
})

关键注意点

  • 优先选择方式一,因为它更贴近真实的exec调用逻辑,能覆盖更多边界场景。
  • 注意exec的回调参数顺序:第一个是错误对象(成功时为null),第二个是stdout,第三个是stderr,不要搞混顺序。

内容的提问来源于stack exchange,提问作者piotrekkr

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 06:53:29