使用Jest为Node.js控制器编写单元测试遇500错误求助
单元测试返回500错误的原因及修复方案
错误原因分析
ContactModel.save的mock未返回Promise
控制器中使用await dummyContact.save(),但你的mockContactSave是普通jest函数,默认返回undefined而非Promise对象,执行await时会抛出错误,直接进入catch分支返回500。- 测试用
req对象缺少必要属性
控制器依赖req.body.variables、parsedPhoneNumber、req.user._id等值,但测试代码未给req定义这些属性,会导致变量未定义触发报错。 AgentModel.findOne的mock冗余且不符合预期mockResolvedValue本身已返回Promise,额外用Promise.resolve包裹属于冗余写法;若mock返回值不符合控制器中agent变量的需求,会导致后续逻辑报错。createCall的mock绑定错误
控制器调用的是createCall函数,但测试中用jest.spyOn(call, 'create'),如果createCall并非call对象下的create方法,这个mock不会生效,导致实际执行时出错。
修正后的测试代码
test('should create a call successfully with valid data', async () => { // 模拟req对象,提供控制器所需的所有属性 const req = { body: { variables: { prospectName: 'Test User' }, // 根据实际逻辑补充生成parsedPhoneNumber的原始数据 }, user: { _id: 'user_123' } }; // 模拟res对象的链式调用方法 const res = { status: jest.fn().mockReturnThis(), json: jest.fn() }; // 修正AgentModel.findOne的mock,直接返回符合需求的agent对象 jest.spyOn(AgentModel, 'findOne').mockResolvedValue({ _id: 'valid_id', agentName: 'test' }); // 让ContactModel.save返回Promise,满足await异步需求 const mockContactSave = jest.fn().mockResolvedValue({ _id: 'contact_123' }); jest.spyOn(ContactModel.prototype, 'save').mockImplementation(mockContactSave); // 正确mock独立的createCall函数(需替换为实际文件路径) jest.mock('../path/to/createCall', () => ({ __esModule: true, default: jest.fn().mockResolvedValue({ _id: 'call_id' }) })); const createCall = require('../path/to/createCall').default; await agentCall(req, res); expect(res.status).toHaveBeenCalledWith(201); expect(res.json).toHaveBeenCalledWith({ status: 'success', call_id: 'call_id' }); expect(mockContactSave).toHaveBeenCalled(); expect(createCall).toHaveBeenCalledWith(expect.objectContaining({ agent: { _id: 'valid_id', agentName: 'test' }, priority: 100 })); });
额外注意事项
- 确保控制器中省略的代码(比如
parsedPhoneNumber生成、agent获取逻辑)都被正确mock覆盖,避免未定义变量报错。 - 若
createCall是独立导入的函数,使用jest.mock直接mock整个模块比spyOn更可靠。 - 测试完成后建议用
mockRestore()清理mock,避免影响其他测试用例。
内容的提问来源于stack exchange,提问作者John
相关产品推荐
相关产品推荐

