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

如何在Jasmine中mock rxjs的webSocket,解决其不可配置的报错问题

问题原因

报错 Error: <spyOnProperty> : webSocket is not declared configurable 的根本原因是:RxJS 6.5.5 中 rxjs/webSocket 导出的 webSocket 是普通函数,不是属性访问器,且ESM规范下的模块导出成员默认是不可配置的,无法通过 spyOnProperty 修改其属性描述符。


解决方案1:模块级Mock(无需修改业务代码)

如果使用Jest作为测试框架,直接对整个rxjs/webSocket模块进行Mock即可,测试代码修改如下:

import * as rxJsWebSocket from 'rxjs/webSocket';
import { Subject } from 'rxjs';
// Mock整个模块,保留原有其他导出,替换webSocket为可打桩的函数
jest.mock('rxjs/webSocket', () => ({
  ...jest.requireActual('rxjs/webSocket'),
  webSocket: jest.fn(),
}));

describe('ChatConnectionService', () => {
  let service: ChatConnectionService;
  const mockSocketSubject = new Subject();

  beforeEach(() => {   
    // 给webSocket函数打桩返回我们的模拟Subject
    (rxJsWebSocket.webSocket as jest.Mock).mockReturnValue(mockSocketSubject as any);
    service = new ChatConnectionService();
  });

  it('should create a new connection when service instantiated', () => {
    expect(rxJsWebSocket.webSocket).toHaveBeenCalledTimes(1);
    expect(rxJsWebSocket.webSocket).toHaveBeenCalledWith('.../chat');
  });
});

如果使用Jasmine作为测试框架,可以用Jasmine对应的模块mock工具,或者改用下面的依赖注入方案。


解决方案2:依赖注入优化(更符合可测试性设计)

只需要对业务代码做小幅调整,将webSocket工厂作为可选依赖注入,完全不需要修改模块导出就能实现测试:

调整后的业务代码

import {webSocket, WebSocketSubject} from 'rxjs/webSocket';
import {delayWhen, retryWhen, take} from 'rxjs/operators';
import {timer, Observable} from 'rxjs';

// 定义webSocket工厂类型
type WebSocketFactory = typeof webSocket;

export class ChatConnectionService {
  private readonly _connection: WebSocketSubject<any>;
  public readonly messages$: Observable<ChatInboundMessage>;

  // 增加可选的工厂参数,生产环境不传就用原生webSocket
  constructor(webSocketFactory: WebSocketFactory = webSocket) {
    this._connection = this.getConnection(webSocketFactory);
    this.messages$ = this._connection.asObservable();
  }

  private getConnection(webSocketFactory: WebSocketFactory): WebSocketSubject<any> {
    return webSocketFactory(`.../chat`);
  }
}

对应的测试代码

import { Subject } from 'rxjs';

describe('ChatConnectionService', () => {
  let service: ChatConnectionService;
  const mockSocketSubject = new Subject();
  // 直接创建mock工厂函数
  const mockWebSocketFactory = jest.fn(() => mockSocketSubject as any);

  beforeEach(() => {   
    service = new ChatConnectionService(mockWebSocketFactory);
  });

  it('should create a new connection when service instantiated', () => {
    expect(mockWebSocketFactory).toHaveBeenCalledTimes(1);
    expect(mockWebSocketFactory).toHaveBeenCalledWith('.../chat');
  });
});

这个方案不需要依赖测试框架的模块Mock能力,耦合度更低,也更符合面向对象的可测试性设计原则。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 05:42:00