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

如何使用Jest模拟Express的Response.setHeader函数以测试自定义中间件

如何使用Jest模拟Express的Response.setHeader函数以测试自定义中间件

我懂你现在卡在哪了——你在mock Express的Response对象时,setHeader的实现触发了递归调用,导致报错this.setHeader is not a function。这是因为你在mock的setHeader里试图调用this.setHeader,但这个mock对象本身没有真正的setHeader方法,相当于自己调用自己,自然会出错。而且你还需要后续断言响应的Content-Type,所以得给mock对象加个存储headers的地方才行。

下面是修正后的测试代码,我会一步步给你解释逻辑:

首先,我们要给mockResponse加一个headers对象用来存设置的头信息,重写setHeader的mock实现把键值对存进去;同时添加getHeader的mock函数,从这个对象里取值。另外别忘了给mockResponse加上statusCode属性,因为你的中间件会直接给它赋值。

it("responds with status code 415 if header 'Content-Type' is not 'application/json'.", () => {
  const contentType = "multipart/form-data";
  
  // 模拟Request对象,和你原来的实现一致
  const mockRequest: Partial<Request> = {
    headers: {
      "Content-Type": contentType,
    },
    is: jest.fn().mockReturnValue(false),
    get: jest.fn().mockReturnValue(contentType),
  };

  // 修正后的Response mock核心部分
  const mockResponse: Partial<Response> = {
    statusCode: 200, // 初始值,中间件会修改为415
    headers: {}, // 用来存储设置的响应头
    setHeader: jest.fn((name, value) => {
      // 把设置的头信息存入mock的headers对象
      (mockResponse.headers as Record<string, string>)[name] = value;
    }),
    getHeader: jest.fn((name) => {
      // 从mock的headers对象中取值,支持后续断言
      return (mockResponse.headers as Record<string, string>)[name];
    }),
    json: jest.fn(),
  };

  const nextFunction: NextFunction = jest.fn();

  const expectedResponse = {
    isSuccessful: false,
    error: `Expected Content-Type 'application/json' but got '${contentType}'.`,
  };

  const middleware = enforceContentTypeApplicationJson();
  middleware(mockRequest as Request, mockResponse as Response, nextFunction);

  // 断言状态码是否正确设置为415
  expect(mockResponse.statusCode).toBe(415);
  // 断言响应Content-Type是否被设置为application/json
  expect(mockResponse.getHeader).toHaveBeenCalledWith('Content-Type');
  expect(mockResponse.getHeader('Content-Type')).toBe('application/json');
  // 断言错误响应体是否正确返回
  expect(mockResponse.json).toHaveBeenCalledWith(expectedResponse);
  // 断言next函数未被调用(因为中间件直接返回了错误响应)
  expect(nextFunction).not.toHaveBeenCalled();
});

关键修正点说明:

  • 新增headers对象:模拟真实Response存储头信息的行为,让setHeader和getHeader有可以操作的数据源。
  • 重写setHeader实现:不再递归调用自己,而是直接将头信息存入mockResponse.headers。
  • 添加getHeader函数:方便后续断言响应头是否符合预期。
  • 新增nextFunction断言:确保中间件在返回错误响应时,不会继续执行后续逻辑,这是测试中间件完整性的重要环节。

如果之后要测试Content-Type符合要求的场景,只需要把mockRequest.is的返回值改成true,然后断言nextFunction被调用即可。

备注:内容来源于stack exchange,提问作者baitendbidz

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.22 10:20:30