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

Jest为Node.js Socket写单元测试:测试通过但无代码覆盖率求助

Socket.io Jest测试通过但无代码覆盖率的问题解决

核心问题分析

你的测试用例能通过,但完全没覆盖服务端代码,根源在这几点:

  1. 测试发送的echo事件,服务端根本没监听,等于没触发任何服务端逻辑
  2. 测试里的断言没正确等待异步操作完成,Jest默认同步执行,不等服务端响应就直接通过了
  3. 服务端模块加载时自动启动服务器,测试环境中可能存在重复启动或资源未正确回收的情况,导致覆盖率收集失效

修复步骤

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 01:31:35