Jest中Node Express应用单测试用例Mock环境变量与导出常量方案咨询
根本原因
你现在的问题是两个错误共同导致的:
- 测试文件顶部提前导入了被测模块,模块顶层的
const { ID_SOURCE, ID_PROVIDER } = constants会在导入时立即执行,此时mock还没运行,拿到的永远是原始值 jest.doMock编写的返回结构和原constants模块不匹配:原模块是export default导出对象,你返回的属性直接挂在模块根节点,结构不对导致mock不生效
正确实现方案
不需要重构业务代码,只需要调整测试逻辑,遵循「先重置模块缓存→先mock→再导入被测模块」的顺序即可,修正后的测试代码如下:
// 注意:顶部不要提前导入被测模块和constants describe('Test module', () => { beforeEach(() => { jest.clearAllMocks(); // 每次测试前重置模块缓存,避免之前导入的模块实例影响结果 jest.resetModules(); }) test('test exception scenario', async () => { // 1. 先mock constants模块,结构要和原模块完全匹配 jest.doMock('./constants', () => { return { __esModule: true, // 原模块是default导出对象,所以mock的值要放在default属性里 default: { ID_SOURCE: undefined, ID_PROVIDER: undefined } } }); // 2. mock完成后再动态导入被测模块 const { moduleUnderTest } = await import('./moduleUnderTest'); // 3. 执行业务测试逻辑 // 这里假设你已经构造了mock的req、res对象 const mockReq = {}; const mockRes = { status: jest.fn().mockReturnThis(), json: jest.fn() }; await expect(moduleUnderTest(mockReq, mockRes)).rejects.toEqual({ err: expect.any(Object) // 匹配你定义的errors.unexpectedError即可 }); }); // 其他测试用例不受影响,不需要mock的话正常导入即可 test('normal scenario', async () => { const { moduleUnderTest } = await import('./moduleUnderTest'); const mockReq = {}; const mockRes = { status: jest.fn().mockReturnThis(), json: jest.fn() }; await moduleUnderTest(mockReq, mockRes); expect(mockRes.status).toHaveBeenCalledWith(200); }) })
可选优化(无侵入兼容更多场景)
如果后续有大量类似测试需求,可以稍微修改常量导出方式,不需要改动业务侧的引用逻辑:
// src/constants.js 调整为getter形式,取值时动态获取process.env export default { get ID_SOURCE() { return process.env.ID_SOURCE }, get ID_PROVIDER() { return process.env.ID_PROVIDER } };
调整后你可以直接在测试用例里修改process.env.ID_SOURCE的值,不需要做模块mock,更灵活。
内容的提问来源于stack exchange,提问作者Jack
相关产品推荐
相关产品推荐

