使用Chai和Mocha测试RESTful API时遇端口占用错误求助
解决Chai+Mocha测试API时的EADDRINUSE错误
错误原因
- 你每个测试用例(
it)都调用了startServer,而app.listen()每次执行都会尝试绑定5000端口。第一个测试启动服务器后,端口被占用,第二个测试再调用时就会抛出EADDRINUSE错误。 - 测试里的
done()调用时机错误,放在了end()回调外面,会导致测试提前结束,断言逻辑可能没执行就标记测试完成。
修复方案
1. 统一管理服务器生命周期(核心修复)
只在所有测试前启动一次服务器,测试结束后关闭,避免重复占用端口:
修改server.ts:
让startServer返回服务器实例,方便后续关闭
import express, { Application } from "express"; import personRouter from "./route/person.route"; import groupRouter from "./route/group.route"; import bodyParser from "body-parser"; const app: Application = express(); // 测试环境用随机端口,避免冲突 const PORT: Number | string = process.env.NODE_ENV === 'test' ? 0 : 5000; app.use(bodyParser.json()); app.use('/person', personRouter) app.use('/group', groupRouter) export function startServer() { // 返回server实例 return app.listen(PORT, () => { const actualPort = (app.listen().address() as any).port; console.log(`Server started on http://localhost:${actualPort}`); }); }
修改test.ts:
用before/after钩子管理服务器启动和关闭,调整done()位置
chai.use(chaiHttp) let server: any; describe('Persons', () => { // 所有测试前启动一次服务器 before(() => { server = startServer(); }); // 所有测试结束后关闭服务器 after((done) => { server.close(done); }); describe('GET /person/', () => { it('check error path', (done) => { chai .request(server) // 直接传入server实例,而非startServer函数 .get("/person/") // 注意路径和server里注册的路由匹配(你之前写的是/persons/,这里要对应) .end((err, res) => { res.should.have.status(422); done(); // 放在回调内,确保断言执行完再结束测试 }); }); }); it('It should get person by first name', (done) => { chai .request(server) .get("/person/Ross") // 修正路径匹配server路由 .end((err, res) => { res.should.have.status(200); res.body.should.be.a('string'); done(); }); }); });
2. 额外注意事项
- 测试路径要和
server.ts里注册的路由严格匹配:你服务器里注册的是/person前缀,测试里不要写成/persons/,否则会触发404或自定义的错误状态码。 - 如果本地有其他服务占用5000端口,也会导致同样错误,可以用
lsof -i :5000(Mac/Linux)或netstat -ano | findstr :5000(Windows)找到占用进程并关闭。
内容的提问来源于stack exchange,提问作者YSH
相关产品推荐
相关产品推荐

