如何使用 Vitest 和 Socket.io 有效编写 WebSockets 集成测试

WebSocket 是一种通信协议,可实现客户端与服务器之间的双向实时数据交换。与遵循请求-响应模式的传统 HTTP 不同,WebSocket 建立的是持久连接,允许数据来回流动,而无需为每次交换重复建立连接。

这种通信模式常用于Web应用程序、网络游戏、聊天系统以及其他需要低延迟、实时通信的场景。集成测试的重点是评估软件应用程序不同组件或模块之间的交互和兼容性。在这种情况下,测试基于 WebSocket 的应用程序可能会面临挑战,原因有以下几点:

1. 异步性质: WebSocket 通信本质上是异步的,数据是实时发送和接收的。这种异步性会导致难以预测事件的顺序,而这在测试场景中至关重要。

2. 定时和同步: WebSocket 应用程序的集成测试需要处理定时问题。在实际场景中,消息可能在不同时间以不同顺序到达,因此设计能考虑这些差异的测试具有挑战性。

3. 模拟和存根:为了在测试过程中控制和隔离 WebSocket 交互,开发人员需要创建模拟 WebSocket 服务器或使用允许他们存根 WebSocket 连接的库。这些额外的抽象层可能容易出错,并增加测试设置的复杂性。

安装

在本示例中,我们将使用 Vitest 和 Socket.io,但也可以使用其他测试运行程序或 WebSocket 库。概念是一样的。

npm install -D vitest
npm install socket.io socket.io-client

示例

在这个示例中,我们将实现一个简单的乘法功能,以展示客户端和服务器之间的通信是如何完成的。

如何使用 Vitest 和 Socket.io 有效编写 WebSockets 集成测试
套接字事件流

首先,客户端发送 “multiply-by-2 “事件,并将数字 5 作为参数。服务器监听了该事件,乘法运算发生,并发出 “multiplied-by-2 “事件。最后,在客户端处理该事件,期望收到 10 作为输出。

实用函数

实用函数对于组织代码和确保一切按照我们的预期运行非常重要。我们需要:

  • 一个辅助函数,用于处理服务器上的套接字事件;
  • 一个负责等待客户端套接字预期事件的函数。
  • 一个设置Web服务器的函数;

处理套接字事件

该函数负责处理服务器上的套接字事件。

import { Server, Socket } from "socket.io";

export function handleSocketEvents(io: Server, socket: Socket) {

  const socketsEvents: Record<string, (data: any) => void> = {
    "multiply-by-2": (data) => {
      const result = data * 2;
      socket.emit("multiplied-by-2", result);
    },
  };

  for (const event in socketsEvents) {
    socket.on(event, socketsEvents[event]);
  }
}

在这段代码中,我们有一个对象,其中包含作为键的待处理事件和作为值的处理函数。如果有其他事件,只需添加到该对象中即可。此外,您还可以使用 “io “来设置其他广播选项。

等待事件

此辅助函数负责让客户端套接字等待来自服务器的事件:

import { Socket as ClientSocket } from "socket.io-client";

export default function waitFor(emitter: ClientSocket, event: string) {
  return new Promise<any>((resolve) => {
    emitter.once(event, resolve);
  });
}

设置Web服务器

该函数使用其他两个函数,启动 Web 服务器、配置套接字服务器并处理客户端套接字连接。

import { Server, Socket } from "socket.io";
import { io as ioc } from "socket.io-client";
import { createServer } from "http";

import { handleSocketEvents } from "./handleSocketEvents";
import waitFor from "./waitForSocketEvent";

export default async function setupTestServer() {
  const httpServer = createServer();

  const io = new Server(httpServer);
  httpServer.listen(PORT);

  const clientSocket = ioc(`ws://localhost:${PORT}`, {
    transports: ["websocket"],
  });

  let serverSocket: Socket | undefined = undefined;
  io.on("connection", (connectedSocket) => {
    serverSocket = connectedSocket;
    handleSocketEvents(io, serverSocket);
  });

  await waitFor(clientSocket, "connect");

  return { io, clientSocket, serverSocket };
}

编写集成测试

设置好测试运行器(本例中为 Vitest)后,让我们来编写测试。首先,我们需要在 “beforeAll “中启动服务器,并在 “afterAll “中关闭连接。

import { Server, Socket } from "socket.io";
import { io as ioc } from "socket.io-client";

import waitFor from "./waitForSocketEvent";

describe("websocket integration test", () => {
  let io: Server;

  let serverSocket: Socket | undefined;
  let clientSocket: ClientSocket;

  beforeAll(async () => {
    const response = await setupTestServer();
    io = response.io;
    clientSocket = response.clientSocket;
    serverSocket = response.serverSocket;
  });

  afterAll(() => {
    io.close();
    clientSocket.close();
  });

});

最后,让我们添加测试用例:

import { Server, Socket } from "socket.io";
import { io as ioc } from "socket.io-client";

import waitFor from "./waitForSocketEvent";

describe("websocket integration test", () => {
  let io: Server;

  let serverSocket: Socket | undefined;
  let clientSocket: ClientSocket;

  beforeAll(async () => {
    const response = await setupTestServer();
    io = response.io;
    clientSocket = response.clientSocket;
    serverSocket = response.serverSocket;
  });

  afterAll(() => {
    io.close();
    clientSocket.close();
  });

  it("should multiply by 2", async () => {
    clientSocket.emit("multiply-by-2", 5);

    const promises = [
      waitFor(clientSocket, "multiplied-by-2"),
    ];

    const [response] = await Promise.all(promises);

    expect(reponse).toBe(10);
  });

});

在这里,”await Promise.all(promises) “并不是必须的,但如果您期待客户端发生多个事件,这是一种避免测试不稳定的有趣方法。

作者:Joao Martins

版权声明:本文内容转自互联网,本文观点仅代表作者本人。本站仅提供信息存储空间服务,所有权归原作者所有。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至1393616908@qq.com 举报,一经查实,本站将立刻删除。

(0)

相关推荐

发表回复

登录后才能评论