Jest单元测试中如何mock嵌套的Response对象参数
NestJS 单元测试 Response 参数 mock 报错解决方案
问题复现
编写接口单元测试时,@Res() 注入的 Response 参数无法正确 mock,调用.json()方法时抛出错误。
控制器方法定义:
async createTenant(@Body() clientDto: ClientDto, @Res() res: any)
控制器内调用逻辑:
return res.status(HttpStatus.BAD_REQUEST).json({ message: 'Client already exists.', });
已尝试的错误mock写法:
const jsonFn = jest.fn().mockImplementation().mockResolvedValueOnce({ message: 'something' }); const res = { status: jest.fn().mockResolvedValueOnce({ json: jsonFn })};
当前.status()调用不报错,但.json()始终抛出异常。
根因分析
错误核心是对status()方法的mock逻辑不符合Express Response的原生行为:
原生Express中res.status()是同步方法,调用后直接返回res实例本身支持链式调用,不存在异步等待。你使用mockResolvedValueOnce会让status()返回一个Promise对象,代码直接在Promise实例上调用.json(),自然会因为找不到方法抛出错误。
可行解决方案
方案1:极简链式mock(推荐,无额外依赖)
利用jest自带的mockReturnThis()实现链式调用上下文返回,完全匹配原生行为:
// 组装mock响应对象 const mockRes = { status: jest.fn().mockReturnThis(), // 调用后返回自身,支持链式调用 json: jest.fn() }; // 执行控制器方法 await controller.createTenant(testClientDto, mockRes); // 断言验证 expect(mockRes.status).toHaveBeenCalledWith(HttpStatus.BAD_REQUEST); expect(mockRes.json).toHaveBeenCalledWith({ message: 'Client already exists.' });
如果需要兼容res.json()直接调用的场景,这个写法也能正常支持。
方案2:手动实现链式返回
如果需要自定义返回逻辑,可以手动让status同步返回挂载了json方法的对象:
const jsonMock = jest.fn(); const mockRes = { status: jest.fn().mockImplementation(() => ({ json: jsonMock })), json: jsonMock };
方案3:TypeScript类型友好写法
如果项目引入了@types/express类型包,可以给mock对象加上类型推导,避免类型报错:
import { Response } from 'express'; const mockRes = { status: jest.fn().mockReturnThis(), json: jest.fn() } as unknown as Response;
避坑提示
- Response上所有支持链式调用的方法(
status/send/set/cookie等),只要代码里是同步链式调用,就不要用mockResolvedValue/mockResolvedValueOnce做异步返回,否则会打断链式调用 - 只有当你自己封装了异步的响应方法、且控制器代码中对方法加了
await时,才需要用异步mock逻辑
内容的提问来源于stack exchange,提问作者user11401
相关产品推荐
相关产品推荐

