You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.28 12:31:01