使用Express、Jest和Supertest时随机Axios错误的排查求助
问题:Supertest全量测试随机出现无堆栈的AxiosError 404错误
- 单个测试文件单独运行全部通过,但全量运行40个文件共280个测试时,总会出现至少一次
AxiosError: Request failed with status code 404错误,有时会出现多次 - 错误随机出现在不同测试文件中,甚至会出现在未发起HTTP请求、未引入Axios的纯单元测试文件内
- 错误发生在测试运行到1/2至3/4阶段,每次出错的文件都不固定
- 已参考Supertest相关issue重构测试的启动/关闭流程,问题未解决
- 错误无有效堆栈跟踪,无法定位来源
测试代码模式
const request = supertest(app); describe("functionName", () => { it("should perform x", async () => { const res = await request.get("/v1/asset"); const { result } = res.body; expect(res.status).toEqual(200); // 其他断言逻辑 }); });
Express App示例
import express from "express"; const app = express(); app.get("/routes", (req, res) => { res.json({}); }); export default app;
运行环境
- Node.js 20.16
- Yarn 4.4.0
- Jest 29.7.0
- Supertest 6.3.4
调试排查方案
1. 开启Axios详细日志
在测试入口文件(如jest.setup.js)中添加Axios拦截器,捕获请求/响应/错误的完整信息:
const axios = require('axios'); // 记录请求详情 axios.interceptors.request.use(request => { console.log(`[AXIOS REQUEST] ${request.method?.toUpperCase()} ${request.url}`); return request; }); // 记录错误详情 axios.interceptors.response.use(response => response, error => { console.error(`[AXIOS ERROR] ${error.response?.status || '未知状态'} 请求地址: ${error.config?.url}`); console.error('错误堆栈:', error.stack); throw error; });
2. 禁用Jest并行测试
随机错误大概率和并行测试的资源冲突有关,先在jest.config.js中关闭并行:
module.exports = { // 其他配置项 maxWorkers: 1, runInBand: true };
若关闭并行后错误消失,说明是测试间的资源竞争(如端口占用、App实例状态污染、数据库连接未清理等)导致。
3. 给每个测试创建独立的App实例
当前所有测试共享同一个app实例,可能出现路由被覆盖、中间件状态污染的情况。修改App导出方式为创建实例的函数:
// app.js 修改后 import express from "express"; const createApp = () => { const app = express(); app.get("/routes", (req, res) => { res.json({}); }); return app; }; export { createApp };
测试文件中每次测试前生成新实例:
const { createApp } = require('../app'); const supertest = require('supertest'); describe("functionName", () => { let request; beforeEach(() => { const app = createApp(); request = supertest(app); }); it("should perform x", async () => { const res = await request.get("/v1/asset"); expect(res.status).toEqual(200); }); });
4. 捕获全局未处理异常
在jest.setup.js中添加全局错误监听,捕获未被测试用例捕获的异常:
process.on('unhandledRejection', (reason, promise) => { console.error('未处理的Promise拒绝:', promise, '原因:', reason); process.exit(1); }); process.on('uncaughtException', (error) => { console.error('未捕获的异常:', error); console.error('异常堆栈:', error.stack); process.exit(1); });
5. 启用Jest详细调试参数
运行测试时添加以下参数,获取更详细的测试执行信息和未关闭资源检测:
yarn test --verbose --detectOpenHandles
内容的提问来源于stack exchange,提问作者Cheyne
相关产品推荐
相关产品推荐

