【问题标题】:Spy on a method passed into a mocked node module监视传递给模拟节点模块的方法
【发布时间】:2022-01-07 13:56:52
【问题描述】:

我正在构建一个将包装SignalR 库的客户端:

export class RealTimeCommunicator {

  /** SignalR hub connection */
  private hubConnection: HubConnection | null = null;

  private buildConnection(url: string): HubConnection {
    return new HubConnectionBuilder()
    .withUrl(url)
    .build();
  }

  public subscribe(onStart: () => void, success: (data: IVehicleInfo) => void, fail?: (err: Error) => void): () => void {
    this.hubConnection = this.buildConnection("/someurl");
    this.hubConnection.on("send", data => {
      success(data);
    });

    this.hubConnection.start()
      .then(onStart)
      .catch(err => fail && fail(err));

    return this.unsubscribe;
  }

  public subscribeToVehicleDetails(vehicleId: number, success: (data: IVehicleInfo) => void, fail?: (err: Error) => void): () => void {
    return this.subscribe(() => this.hubConnection!.invoke("EnrolInVehicleGroupAsync", vehicleId), success, fail);
  }

我想测试它,但是模拟了SignalR,所以我在解决方案中添加了__mocks__/@aspnet/signalr.ts

let SignalR = jest.genMockFromModule("@aspnet/signalr");

class HubConnection {

  public on(methodName: string, callback: () => string): Promise<void> {
    this.successCallback = callback;
    return Promise.resolve()
  }

  public start(): Promise<void> { return Promise.resolve() }

  public successCallback: () => string = () => "failure";
}

let hubConnection = new HubConnection();

let HubConnectionBuilder = () => ({
  withUrl: (url) => ({
    build: () => hubConnection
  })
});

SignalR = {
  HubConnectionBuilder: HubConnectionBuilder,
  HubConnection: hubConnection
};

module.exports = SignalR;

我正在尝试监视 on 方法以确保它被调用,并作为延伸目标确认我的成功处理程序已正确注册。

import { RealTimeCommunicator } from "./RealTimeCommunicator";
jest.mock('SignalR');

describe("RTC", () => {
  test("foo", () => {
    const ConnectionBuilder = require("SignalR").HubConnectionBuilder;

    const connection = new ConnectionBuilder().withUrl("").build();

    const spy = jest.spyOn(connection, 'on');
    expect(spy).toHaveBeenCalled();  //Expectation fails
    const successText = "success!";
    const successCallBack: () => string = () => successText;
    const rtc = new RealTimeCommunicator();

    rtc.subscribeToVehicleDetails(1, successCallBack, _ => _);
    expect(connection.successCallback()).toBe(successText); // connection.successCallback is undefined
  })
});

如果我在 SignalR 模拟中放置断点,我可以看到 on 正在被调用,但间谍没有看到它。我用螺栓固定在我的模拟上的successCallback 也以undefined 的形式返回

【问题讨论】:

    标签: typescript unit-testing jestjs


    【解决方案1】:

    您能否提供任何工作示例(例如以回购的形式)来重现您的问题?据我所知,提供的代码sn-ps存在一些缺陷。

    首先,为什么jest.mock('SignalR'); 实际工作? SignalR 不是应该抛出错误的模块。您应该模拟您实际导入的模块:jest.mock('@aspnet/signalr');。除此之外,您的第一部分测试包括测试第三方库 - 除了检查您的模拟是否正常工作之外,您为什么要这样做?

    其次,您正在检查 on 方法是否在创建间谍后立即被调用。不过,间谍只记录创建后的调用。您可能想要的是让 on 方法默认成为间谍:

    // in __mocks__/@aspnet/signalr.ts
    
    class HubConnection {
    
      public on = jest.fn().mockImplementation((methodName: string, callback: () => string) => {
        this.successCallback = callback;
        return Promise.resolve()
      });
    
    
      // ...
    
    }
    

    第三,您在测试中创建的 连接 与您稍后使用 subscribeToVehicleDetails 创建的连接不同,因此 successCallback 仍会返回“失败”如果它会工作。

    【讨论】:

      【解决方案2】:

      你已经接近了,你只需要做两处改变。


      返回success(data)的结果:

      public subscribe(onStart: () => void, success: (data: IVehicleInfo) => void, fail?: (err: Error) => void): () => void {
        this.hubConnection = this.buildConnection("/someurl");
        this.hubConnection.on("send", data => {
          return success(data);   // return the result
        });
      
        this.hubConnection.start()
          .then(onStart)
          .catch(err => fail && fail(err));
      
        return this.unsubscribe;
      }
      

      等待断言spy 已被调用,直到之后你调用rtc.subscribeToVehicleDetails

      const spy = jest.spyOn(connection, 'on');
      const successText = "success!";
      const successCallBack: () => string = () => successText;
      const rtc = new RealTimeCommunicator();
      
      rtc.subscribeToVehicleDetails(1, successCallBack, _ => _);
      expect(spy).toHaveBeenCalled();   // SUCCESS
      expect(connection.successCallback()).toBe(successText);   // SUCCESS
      

      【讨论】:

        猜你喜欢
        • 2022-01-03
        • 2019-12-09
        • 1970-01-01
        • 1970-01-01
        • 2019-12-02
        • 1970-01-01
        • 1970-01-01
        • 2015-03-31
        • 1970-01-01
        相关资源
        最近更新 更多