如何在Jest中Mock子进程中Grunt任务调用的request模块?
问题分析
你猜的没错,Jest 的 Mock 仅作用于当前进程,通过 exec 启动的子进程是完全独立的 Node.js 实例,不会继承主进程的 Mock 模块,所以子进程里调用的 request 还是原模块。
解决方案
这里提供几个可行的解决思路:
1. 直接测试任务核心逻辑(推荐)
把 Grunt 任务里依赖 request 的核心逻辑抽成单独模块,测试时直接导入该模块验证,无需启动子进程执行 Grunt 命令,这样 Jest 的 Mock 就能正常生效。
示例代码:
task-logic.js
const request = require('request'); module.exports = function fetchData(url, callback) { request(url, function(error, response, body) { // 原任务中的业务逻辑 callback(error, response, body); }); };
task.js
const fetchData = require('./task-logic'); // Grunt 任务注册逻辑 grunt.registerTask('task', function() { const done = this.async(); fetchData('目标URL', function(error, response, body) { // 任务后续处理逻辑 done(); }); });
task.spec.js
const fetchData = require('./task-logic'); const request = require('request'); jest.mock('request'); describe('UT for something', () => { it('should pass', async () => { request.mockImplementation((url, cb) => { cb(undefined, undefined, 'mocked response'); }); await new Promise((resolve) => { fetchData('测试URL', resolve); }); // 断言逻辑,比如验证request被正确调用 expect(request).toHaveBeenCalledWith('测试URL', expect.any(Function)); }); });
2. 给子进程注入Mock模块
如果必须通过子进程执行Grunt任务,可以通过环境变量引导子进程优先加载Mock版本的request:
- 先编写Mock版
request模块,比如__mocks__/request.js:
module.exports = function(url, cb) { cb(undefined, undefined, 'mocked response'); };
- 执行子进程时,设置
NODE_PATH环境变量让子进程优先加载Mock模块:
const exec = require('child_process').exec; describe('UT for something', () => { it('should pass', async () => { const execChild = () => { return new Promise((resolve, reject) => { exec('grunt task', { env: { ...process.env, NODE_PATH: './__mocks__:' + (process.env.NODE_PATH || '') } }, (error, stdout, stderr) => { if (error) reject(error); resolve(stdout || stderr); }); }); }; await execChild(); // 后续断言逻辑 }); });
注意:Mock模块的导出结构必须和原request模块一致,否则会引发逻辑错误。
3. 通过环境变量切换逻辑分支
在task.js中根据环境变量判断是否加载Mock模块:
let request; if (process.env.NODE_ENV === 'test') { request = require('./__mocks__/request'); } else { request = require('request'); } // 后续Grunt任务注册及业务逻辑
执行子进程时设置测试环境变量:
exec('grunt task', { env: { ...process.env, NODE_ENV: 'test' } }, ...);
内容的提问来源于stack exchange,提问作者Sachin
相关产品推荐
相关产品推荐

