Jest为Node.js Socket写单元测试:测试通过但无代码覆盖率求助
Socket.io Jest测试通过但无代码覆盖率的问题解决
核心问题分析
你的测试用例能通过,但完全没覆盖服务端代码,根源在这几点:
- 测试发送的
echo事件,服务端根本没监听,等于没触发任何服务端逻辑 - 测试里的断言没正确等待异步操作完成,Jest默认同步执行,不等服务端响应就直接通过了
- 服务端模块加载时自动启动服务器,测试环境中可能存在重复启动或资源未正确回收的情况,导致覆盖率收集失效
修复步骤
1. 重构服务端代码(可控启动/关闭)
把服务器启动逻辑封装成函数,避免模块加载时自动启动,方便测试时控制生命周期:
const express = require("express"); const app = express(); let items = []; let server; let io; function startServer(port = 3000) { server = app.listen(port, () => { console.log(`Listening on port ${port}`); }); io = require("socket.io")(server, { cors: { origin: "http://localhost:4200", methods: ["GET", "POST"], }, }); io.on("connection", (socket) => { console.log("a user connected"); socket.on("message", (message) => { console.log(message); io.emit("message", `${message}`); }); socket.on("disconnect", () => { console.log("a user disconnected!"); }); }); return { server, io }; } function stopServer() { if (server) { server.close(); } } module.exports = { startServer, stopServer, io };
2. 修正测试代码(触发服务端逻辑+等待异步操作)
修改测试用例,触发服务端实际监听的事件,并用done回调确保异步操作完成:
const ioClient = require('socket.io-client'); const { startServer, stopServer } = require('../src/socket/index'); describe('Socket.io server tests', () => { let server; let ioServer; let clientSocket; beforeAll((done) => { // 用随机端口启动服务,避免端口冲突 const { server: s, io: ioS } = startServer(0); server = s; ioServer = ioS; const port = server.address().port; // 连接到服务端随机端口 clientSocket = ioClient.connect(`http://localhost:${port}`, { reconnectionDelay: 0, forceNew: true }); clientSocket.on('connect', done); }); afterAll((done) => { // 测试结束后清理资源 if (clientSocket.connected) { clientSocket.disconnect(); } stopServer(); done(); }); it('should trigger connection event on server', (done) => { // 验证服务端已识别客户端连接 expect(ioServer.sockets.sockets.size).toBe(1); done(); }); it('should process and broadcast "message" event', (done) => { const testMsg = 'Hello Jest'; clientSocket.emit('message', testMsg); // 监听服务端返回的消息 clientSocket.once('message', (receivedMsg) => { expect(receivedMsg).toBe(testMsg); done(); }); }); it('should trigger disconnect event on server', (done) => { clientSocket.disconnect(); clientSocket.once('disconnect', () => { expect(ioServer.sockets.sockets.size).toBe(0); done(); }); }); });
3. 配置Jest覆盖率收集
确保jest.config.js里正确指定要收集覆盖率的文件路径:
module.exports = { collectCoverage: true, collectCoverageFrom: [ 'src/socket/**/*.js' // 替换成你的服务端Socket代码路径 ], coverageReporters: ['html', 'text'] };
为什么之前的测试能通过?
因为你的测试没有等待异步操作完成,Jest执行完同步代码就直接判定通过了,实际上根本没走到服务端的事件处理逻辑。现在用done回调强制Jest等待异步操作完成,同时触发服务端实际监听的事件,就能正确收集到覆盖率了。
内容的提问来源于stack exchange,提问作者vinuta
相关产品推荐
相关产品推荐

