如何使用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
相关产品推荐
相关产品推荐

