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

如何用Jest模拟Node.js HTTP请求测试自定义重定向处理器?

嘿,针对你用Jest测试HTTP重定向处理器遇到的两个问题,我来给你一步步梳理解决方案:


1. 构造模拟的HTTP请求

你的redirectHttpToHttps函数依赖Node.js的http.IncomingMessage(也就是req对象),但实际上你只需要模拟它的核心属性——比如url、method,如果你的逻辑需要完整URL的话,还要加上headers.host来拼接域名。

比如要模拟一个指向http://google.com/mytest的GET请求:

const mockReq = {
  url: '/mytest', // Node.js的req.url默认是域名后的路径部分
  method: 'GET',
  headers: {
    host: 'google.com'
  }
};

如果你的处理器里直接用req.url去匹配url_from(而不是完整URL),那去掉headers.host就行,根据你实际的逻辑调整。


2. 断言HTTP响应的状态码与响应头

对于res对象(http.ServerResponse),我们需要模拟它的writeHead和end方法——这两个是你重定向逻辑里肯定会用到的。用Jest的jest.fn()创建模拟方法,就能轻松追踪它们的调用参数。

比如:

const mockRes = {
  writeHead: jest.fn(), // 模拟设置状态码和响应头的方法
  end: jest.fn() // 模拟结束响应的方法
};

调用处理器后,就可以用Jest的断言来验证:

  • writeHead是否传入了预期的状态码(比如301)和Location重定向地址
  • end是否被调用(确认响应正常结束)

完整的测试用例示例

结合你的测试代码,修改后的test_redirect.jest.js应该是这样的(我还补了异步处理的部分,因为数据库插入是异步的,必须等它完成再测试):

const db = require('../src/db.js');
const redirect = require('../src/handle_http.js');

// 简单的错误处理回调
const handleDbError = (error) => {
  if (error) throw new Error(`DB Error: ${error.message}`);
};

test("should redirect exact match GET request with 301", async () => {
  // 初始化内存数据库并插入测试数据
  const dbHandler = db(':memory:');
  await new Promise((resolve, reject) => {
    dbHandler.exec(`
      INSERT INTO redirect (url_from,url_to,method,http_status_code,use_in_http,exact_match) VALUES
      ('http://google.com/mytest','http://yahoo.com','GET',301,1,1),
      ('http://google.com/mytest2','http://yandex.com','GET',302,1,0),
      ('http://google.com?q=ikariam','http://yandex.com','GET',302,1,1),
      ('http://example.com/products','https://fakestoreapi.com/products','POST',308,1,1),
      ('http://example.net/products','https://fakestoreapi.com/products','POST',308,1,0),
      ('http://example.net','https://fakestoreapi.com/products','POST',308,1,0);
    `, (error) => {
      if (error) reject(error);
      resolve();
    });
  });

  // 构造匹配第一条数据的模拟请求
  const mockReq = {
    url: '/mytest',
    method: 'GET',
    headers: { host: 'google.com' }
  };

  // 构造模拟响应对象
  const mockRes = {
    writeHead: jest.fn(),
    end: jest.fn()
  };

  // 调用重定向处理器
  redirect.redirectHttpToHttps(dbHandler, mockReq, mockRes);

  // 断言响应符合预期
  expect(mockRes.writeHead).toHaveBeenCalledWith(301, {
    Location: 'http://yahoo.com'
  });
  expect(mockRes.end).toHaveBeenCalled();
});

// 再添加一个非精确匹配的POST请求测试
test("should redirect non-exact match POST request with 308", async () => {
  const dbHandler = db(':memory:');
  await new Promise((resolve, reject) => {
    dbHandler.exec(`
      INSERT INTO redirect (url_from,url_to,method,http_status_code,use_in_http,exact_match) VALUES
      ('http://example.net/products','https://fakestoreapi.com/products','POST',308,1,0);
    `, (error) => {
      if (error) reject(error);
      resolve();
    });
  });

  const mockReq = {
    url: '/products/123', // 非精确匹配/products路径
    method: 'POST',
    headers: { host: 'example.net' }
  };

  const mockRes = {
    writeHead: jest.fn(),
    end: jest.fn()
  };

  redirect.redirectHttpToHttps(dbHandler, mockReq, mockRes);

  expect(mockRes.writeHead).toHaveBeenCalledWith(308, {
    Location: 'https://fakestoreapi.com/products'
  });
  expect(mockRes.end).toHaveBeenCalled();
});

几个关键注意点

  1. 异步处理:数据库插入是异步操作,必须用async/await或者done回调等待它完成,否则测试会在数据插入前执行,导致逻辑找不到匹配项。
  2. 测试隔离:每个测试用例最好用独立的数据库实例(你用的:memory:刚好符合),或者在afterEach钩子中清空表,避免测试用例之间互相干扰。
  3. 异步处理器:如果你的redirectHttpToHttps函数内部是异步的(比如SQL查询用了回调或Promise),记得让测试等待异步操作完成——比如把函数改成返回Promise,然后在测试里await redirect.redirectHttpToHttps(...)。

内容的提问来源于stack exchange,提问作者Dimitrios Desyllas

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 18:02:25