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

Angular中如何测试私有属性Socket的on方法是否被调用

验证SocketService中initializeSocket方法的socket.on调用情况

下面提供两种实用的测试方案,无需直接访问私有属性即可完成验证:

方案1:通过依赖注入解耦,便于Mock测试

原代码中Socket实例是内部创建的,不利于测试。可以修改类的构造函数,允许注入Socket的创建逻辑(工厂函数),这样测试时能传入Mock的Socket实例:

修改后的类代码:

import {Socket} from 'socket.io-client';

// 定义Socket工厂类型
type SocketFactory = () => Socket;

export class SocketService {
  private socket: Socket;
  private readonly socketFactory: SocketFactory;

  // 注入Socket工厂,默认使用实际创建逻辑
  constructor(socketFactory: SocketFactory = () => { /* 原创建Socket的逻辑 */ }) {
    this.socketFactory = socketFactory;
  }

  public initializeSocket() {
    if(this.socket) { return; }
    this.socket = this.socketFactory();
    this.socket.on('connect', () => this.processConnect() );
  }

  private processConnect() {
    // ...
  }
}

测试代码(以Jest为例):

import { SocketService } from './socket.service';
import { Socket } from 'socket.io-client';

describe('SocketService', () => {
  it('should call socket.on with "connect" event when initializeSocket is called', () => {
    // 创建Mock的Socket实例
    const mockSocket = {
      on: jest.fn()
    } as unknown as Socket;

    // 传入返回mockSocket的工厂函数,创建服务实例
    const service = new SocketService(() => mockSocket);
    
    service.initializeSocket();

    // 验证on方法的调用参数和次数
    expect(mockSocket.on).toHaveBeenCalledWith('connect', expect.any(Function));
  });

  it('should not call socket.on again if socket already exists', () => {
    const mockSocket = {
      on: jest.fn()
    } as unknown as Socket;

    const service = new SocketService(() => mockSocket);
    
    service.initializeSocket();
    service.initializeSocket(); // 第二次调用

    // 验证on方法仅被调用一次
    expect(mockSocket.on).toHaveBeenCalledTimes(1);
  });
});

方案2:直接Mock socket.io-client模块

如果不想修改原类结构,可以通过测试框架Mock整个socket.io-client模块,跟踪Socket类的实例方法调用:

测试代码(Jest为例):

import { SocketService } from './socket.service';
import { Socket } from 'socket.io-client';

// Mock整个socket.io-client模块
jest.mock('socket.io-client', () => {
  const mockOn = jest.fn();
  return {
    Socket: jest.fn().mockImplementation(() => ({
      on: mockOn
    }))
  };
});

describe('SocketService', () => {
  it('should call socket.on with "connect" event', () => {
    const service = new SocketService();
    service.initializeSocket();

    // 获取Mock的Socket实例,验证on方法调用
    const mockSocketInstance = (Socket as jest.Mock).mock.instances[0];
    expect(mockSocketInstance.on).toHaveBeenCalledWith('connect', expect.any(Function));
  });
});

注意事项

  • 无需直接访问私有属性this.socket,通过Mock依赖的方式即可完成验证,符合黑盒测试原则。
  • 若使用Vitest,只需将jest.fn()替换为vi.fn(),jest.mock()替换为vi.mock()即可。

内容的提问来源于stack exchange,提问作者Kerwen

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 04:55:42