ASP.NET Core 2.1与SignalR测试指南

在最新的ASP.NET Core2.1版本中,SignalR库的发布为开发者提供了一种在Web服务器和浏览器之间进行双向通信的新方式。SignalR支持通过HTTP或WebSockets进行通信。本文不会深入探讨SignalR的工作原理,因为官方文档已经提供了丰富的教程和示例。本文将重点介绍如何对SignalR Hub进行单元测试,以确保服务器发送的信号是正确的。

要进行这项测试,首先需要设置一个ASP.NET Core2.1的Web项目,不需要添加任何身份验证或其他细节。接着,创建一个.NET Core测试项目,并引用以下NuGet包:

Microsoft.NET.Test.Sdk v15.7.2 NUnit v3.10.1 NUnit3TestAdapter v3.10.0 Moq 4.8.3

这些是进行单元测试时最基本的包。然后,从测试项目引用自己的Web应用程序。

接下来,创建一个名为SimpleHub的Hub类,如下所示:

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文件中,添加以下代码:

services.AddSignalR(); app.UseSignalR(builder => builder.MapHub("/hub"));

这样,就有一个可以工作的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 mockClients = new Mock(); Mock mockClientProxy = new Mock(); 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(o => o != null && o.Length == 1 && ((object[])o[0]).Length == 3), default(CancellationToken)), Times.Once); } } }

现在让分解一下:

按照测试的标准,测试分为三个部分:arrange(测试设置),act(要测试的实际逻辑),和assert(测试逻辑是否按预期行为)。SignalRHub本身并没有包含太多逻辑,它们所做的只是将工作委托给IHubCallerClients,而IHubCallerClients在发送消息时会将调用委托给IClientProxy。

然后为IHubCallerClients和IClientProxy创建模拟对象。在第22行,设置模拟,以便当调用All属性时,返回IClientProxy模拟的实例。

然后创建一个SimpleHub,并告诉它使用模拟对象作为其Clients委托。现在完全控制了流程。

调用SimpleHub.Welcome,这开始了向连接的客户端发送消息的整个过程。在第35行,检查IHubCallerClients模拟是否确实被使用,并且只被调用了一次。

第37行更具体:首先,检查SendCoreAsync方法的调用,这是因为Hub中使用的方法SendAsync实际上是一个扩展方法,它只是将参数包装成一个数组并发送给SendCoreAsync。检查确实要在客户端调用的方法实际上是命名为welcome。

然后检查发送的消息不是null(因为是一个and语句,如果是null,它会短路),它有一个长度为1(记得从前面的消息被包装到一个额外的数组),并且该集合的第一个元素确实是一个包含3个项目的对象数组(消息)。

还需要提供CancelationToken的默认值,因为Moq不能验证可选参数。最后,检查消息只发送了一次。

沪ICP备2024098111号-1
上海秋旦网络科技中心:上海市奉贤区金大公路8218号1幢 联系电话:17898875485