运行Node.js测试用例时UnhandledPromiseRejectionWarning的解决方法
问题:Node.js原生HTTP服务测试时的未处理Promise拒绝错误
我正在为Node.js原生HTTP服务编写测试用例,执行时出现未处理Promise拒绝警告。注意:我没有测试脚本的修改权限,只能调整自身的Node.js业务代码,且必须使用http模块而非Express框架。
Node.js业务代码
var http = require('http'); const requestListener = function (req, res) { let url = req.url; let method = req.method; let valid = false; let ar = url.split("/"); let id = 0; if(method == 'GET') { if(ar.length == 3) { valid = true; } } if(valid) { res.setHeader("Content-Type", "application/json"); res.writeHead(200); res.end(`{"message": "Project found"}`); } else { res.setHeader("Content-Type", "application/json"); res.writeHead(404); res.end(`{"message": "Not Found"}`); } return; }; const host = 'localhost'; const port = 8000; const server = http.createServer(requestListener); server.listen(port, host, () => { console.log(`Server is running on http://${host}:${port}`); });
测试代码(无法修改)
const chai = require('chai'); const chaiHttp = require('chai-http'); const server = require('../index'); const Promise = require('bluebird'); const should = chai.should(); chai.use(chaiHttp); describe('sample', () => { it('Should return 404 for wrong path', (done) => { chai.request(server) .get('/') .then(response => { response.status.should.eql(404); done() }) }); });
测试执行错误信息
✓ Should return 404 for wrong path (node:7739) UnhandledPromiseRejectionWarning: AssertionError: expected 200 to deeply equal 400 at /projects/test/index.spec.js:25:40 at processTicksAndRejections (internal/process/task_queues.js:95:5) (node:7739) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 1) (node:7739) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code.
疑问
- 测试用例显示通过(有勾选标记),但为何会输出错误信息?
- Postman访问
localhost:8000/能得到预期的404响应,如何修复测试时的错误?
解决方案
问题根源
- 业务代码在模块导入时自动启动HTTP服务器,导致测试过程中多次启动服务器,引发未关闭的连接和Promise拒绝。
- 错误信息中的
expected 200 to deeply equal 400说明测试代码中存在其他未展示的测试用例,业务代码的路径判断逻辑存在漏洞,无法覆盖这些场景。
修改Node.js业务代码
只能调整业务代码,核心是让服务器由测试代码控制启动/关闭,同时修复路径判断逻辑:
var http = require('http'); const requestListener = function (req, res) { let url = req.url; let method = req.method; let valid = false; let ar = url.split("/"); // 修复路径判断:仅允许类似"/xxx/xxx"的合法GET路径,排除空分段 if(method === 'GET') { valid = ar.length === 3 && ar[1].trim() !== '' && ar[2].trim() !== ''; } // 统一设置响应头,避免重复代码 res.setHeader("Content-Type", "application/json"); if(valid) { res.writeHead(200); res.end(`{"message": "Project found"}`); } else { res.writeHead(404); res.end(`{"message": "Not Found"}`); } }; // 创建服务器但不自动启动 const server = http.createServer(requestListener); // 导出服务器实例供测试代码使用 module.exports = server; // 仅当直接运行该文件时才启动服务器(如node index.js) if (require.main === module) { const host = 'localhost'; const port = 8000; server.listen(port, host, () => { console.log(`Server is running on http://${host}:${port}`); }); }
修改说明
- 避免自动启动服务器:通过
require.main === module判断,仅在直接运行文件时启动服务器,模块导入时只导出服务器实例,让chai-http控制服务器生命周期,避免重复启动。 - 修复路径判断逻辑:原来的
ar.length == 3会误判"/a/"这类路径为合法,修改后确保两级路径分段都非空,符合预期的合法路径格式。 - 统一响应头设置:将
res.setHeader移到分支外,减少重复代码,确保所有响应都正确设置Content-Type。
额外说明
错误信息中的expected 200 to deeply equal 400对应测试代码中其他未展示的测试用例,修改后的业务代码对所有非合法请求统一返回404,可覆盖这些场景,消除未处理的Promise拒绝。
内容的提问来源于stack exchange,提问作者Learner
相关产品推荐
相关产品推荐

