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

单元测试Mock ASP.NET Core SignalR HubConnection,仍需用IHubProxy这类Wrapper吗?

在单元测试中Mock ASP.NET Core SignalR的HubConnection:是否还需要IHubProxy包装器?

答案是不需要,现在有更简洁的方案,完全不用额外维护这类包装器,直接Mock HubConnection本身即可。

为什么不用包装器?

  • 包装器会增加额外代码量,每次HubConnection更新API都要同步维护,徒增维护成本
  • 现代Mock框架(比如Moq)支持直接Mock非密封类的虚方法,而HubConnection的核心方法(如InvokeAsync、SendAsync、On)都是虚方法,完全可以直接Mock

直接Mock HubConnection的示例(用Moq)

1. Mock调用服务端方法的场景

// 创建HubConnection的Mock实例
var mockHubConn = new Mock<HubConnection>();

// Mock InvokeAsync(有返回值的调用)
mockHubConn.Setup(conn => conn.InvokeAsync<string>("GetServerData", It.IsAny<object[]>(), It.IsAny<CancellationToken>()))
           .ReturnsAsync("MockedServerResponse");

// Mock SendAsync(无返回值的调用)
mockHubConn.Setup(conn => conn.SendAsync("SendDataToServer", It.IsAny<object[]>(), It.IsAny<CancellationToken>()))
           .Returns(Task.CompletedTask);

// 将Mock实例注入到被测服务中
var yourService = new YourBusinessService(mockHubConn.Object);

2. 测试客户端接收消息的场景

如果需要验证客户端注册的消息回调是否正常工作,可以直接捕获回调并手动触发:

string receivedMsg = null;

// 先在Mock的HubConnection上注册回调
mockHubConn.Object.On<string>("ReceiveMessage", msg => {
    receivedMsg = msg;
    return Task.CompletedTask;
});

// 手动触发回调(模拟服务端推送消息)
// 这里通过反射获取注册的回调并执行
var handlers = mockHubConn.Object.GetType()
    .GetField("_handlers", BindingFlags.Instance | BindingFlags.NonPublic)?
    .GetValue(mockHubConn.Object);
var callback = handlers?.GetType()
    .GetMethod("GetHandler")?
    .Invoke(null, new object[] { "ReceiveMessage", new[] { typeof(string) } }) as Func<string, Task>;

await callback?.Invoke("TestMessageFromServer");

// 验证回调是否正确执行
Assert.Equal("TestMessageFromServer", receivedMsg);

总结

直接Mock HubConnection是更优的方案:

  • 省去包装器的维护成本
  • 测试逻辑更贴近生产代码的实际调用方式
  • 完全覆盖核心的SignalR客户端交互场景

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.08 15:42:23