测试 ASP.NET Core 2.1 中的 SignalR Hub





0/5 (0投票)
如何在 ASP.NET Core 2.1 中测试 SignalR Hub
引言
正如你们中的一些人可能已经听说的,ASP.NET Core 2.1.0 已于上个月底发布。此版本附带的功能之一是SignalR的发布,对于不了解它的人来说,它是一个库,允许在 Web 服务器和浏览器之间通过 HTTP 或 WebSockets 进行双向通信。
我将不会详细介绍 SignalR 的工作原理,因为上面链接中提供了相当多的文档,包括一个教程,所以在这篇文章中,我们将看看如何对 SignalR hub 进行单元测试,以便我们可以确保我们的服务器正在发送正确的信号。
此练习的代码可以在这里找到。
设置
创建 Web 项目
在这篇文章中,我们将创建一个新的 ASP.NET Core 2.1 应用程序(应该适用于所有 ASP.Core Web 应用程序模板),不带身份验证或其他详细信息,因为我们对此不感兴趣。
创建测试项目
然后我们将创建一个 .NET Core 测试项目,该项目将引用以下 Nuget 包
我认为这些是我进行单元测试时最少需要使用的软件包。
然后我们从测试项目中引用我们自己的 Web 应用程序。
创建 Hub
现在我们已经完成了项目,让我们在 Web 应用程序中注册一个简单的 hub。
让我们在 Web 应用程序中创建一个名为 SimpleHub
的文件,它看起来像这样
namespace SignalRWebApp
{
using System.Threading.Tasks;
using Microsoft.AspNetCore.SignalR;
public class SimpleHub : Hub
{
public override async Task OnConnectedAsync()
{
await Welcome();
await base.OnConnectedAsync();
}
public async Task Welcome()
{
await Clients.All.SendAsync("welcome", new[]
{ new HubMessage(), new HubMessage(), new HubMessage() });
}
}
}
为此,我们还将创建一个 HubMessage
类,它只是一个占位符,这样我们就不会使用匿名对象,它看起来像这样
namespace SignalRWebApp
{
public class HubMessage
{
}
}
这将向连接到 hub 的任何人发送一系列 3 条消息。我选择了任意数字 3,以便我也可以测试服务器发送的消息的内容和长度。
在Startup.cs中,我们添加以下行
- 在
ConfigureServices
中,我们添加行services.AddSignalR();
- 在
Configure
中,在app.UseMvc
行之前,我们添加行app.UseSignalR(builder => builder.MapHub("/hub"));
这样,我们现在就有了一个可以供客户端连接的工作 hub。
创建客户端连接
为了进行测试,我们将使用此处找到的安装步骤来安装 JavaScript SignalR,以便我们可以在浏览器中使用它并编写我们自己的脚本,如下所示
@section Scripts
{
$(document).ready(() => {
const connection = new signalR.HubConnectionBuilder().withUrl("/hub").build();
connection.on("welcome", (messages) => {
alert(messages);
});
connection.start().catch(err => console.error(err.toString()));
});
}
现在,我们只需要运行网站并查看我们收到一个带有 3 个对象的警报。
测试
现在我们进入有趣的部分,我将粘贴测试代码,然后进行分解。
namespace SignalRWebApp.Tests
{
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.SignalR;
using Moq;
using NUnit.Framework;
[TestFixture]
public class Test
{
[Test]
public async Task SignalR_OnConnect_ShouldReturn3Messages()
{
// arrange
Mock<IHubCallerClients> mockClients = new Mock<IHubCallerClients>();
Mock<IClientProxy> mockClientProxy = new Mock<IClientProxy>();
mockClients.Setup(clients => clients.All).Returns(mockClientProxy.Object);
SimpleHub simpleHub = new SimpleHub()
{
Clients = mockClients.Object
};
// act
await simpleHub.Welcome();
// assert
mockClients.Verify(clients => clients.All, Times.Once);
mockClientProxy.Verify(
clientProxy => clientProxy.SendCoreAsync(
"welcome",
It.Is<object[]>(o => o != null && o.Length == 1 && ((object[])o[0]).Length == 3),
default(CancellationToken)),
Times.Once);
}
}
}
现在我们来分解一下
- 在真正的测试精神下,测试分为 3 个部分:Arrange(处理测试设置)、Act(执行我们想要测试的实际逻辑)和Assert(测试我们的逻辑是否如我们所愿)。
- SignalR hubs 实际上不包含太多逻辑,它们所做的就是将工作委托给
IHubCallerClients
,然后当发送消息时,IHubCallerClients
会将调用委托给IClientProxy
- 然后我们为
IHubCallerClients
和IClientProxy
创建一个 mock 对象 - 在第 22 行,我们设置 mock 对象,以便在调用
All
属性时,返回IClientProxy
mock 对象的实例。 - 然后我们创建一个
SimpleHub
并告诉它使用我们的 mock 对象进行Clients
委托。现在我们对流程拥有完全的控制权。 - 我们调用
SimpleHub.Welcome
,这会启动将消息发送到已连接客户端的整个过程。 - 在第 35 行,我们检查
IHubCallerClients
的 mock 对象确实被使用了,并且只被调用了一次。 - 第 37 行更具体
- 首先,我们正在检查对
SendCoreAsync
的调用,因为我们在 hub 中使用的SendAsync
方法实际上是一个扩展方法,它只是将参数包装到数组中并将其发送到SendCoreAsync
。 - 我们检查在客户端实际要调用的方法确实命名为
welcome
。 - 然后我们检查发送的消息不是
null
(作为一个*and*子句,如果它是null
,它会短路),它有一个Length
为 1(记住,早些时候消息被包装在一个额外的数组中),并且该集合的第一个元素确实是一个包含 3 个项目(我们的消息)的对象数组。 - 由于
Moq
无法验证可选参数,我们还必须为CancelationToken
提供默认值。 - 最后,我们检查消息只发送了一次。
- 首先,我们正在检查对
至此,我们已经测试了我们的 SignalR
hub 确实按预期工作。使用这种方法,在一个单独的项目中,我还可以细致地测试所有传入的内容,包括消息只发送给一个特定客户端的情况。
这就是我们关于测试 ASP.NET Core 2.1.0 的 SignalR 的帖子。
希望您喜欢,下次再见,