65.9K
CodeProject 正在变化。 阅读更多。
Home

测试 ASP.NET Core 2.1 中的 SignalR Hub

2018年11月13日

CPOL

4分钟阅读

viewsIcon

13864

如何在 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);
        }
    }
}

现在我们来分解一下

  1. 在真正的测试精神下,测试分为 3 个部分:Arrange(处理测试设置)、Act(执行我们想要测试的实际逻辑)和Assert(测试我们的逻辑是否如我们所愿)。
  2. SignalR hubs 实际上不包含太多逻辑,它们所做的就是将工作委托给 IHubCallerClients,然后当发送消息时,IHubCallerClients 会将调用委托给 IClientProxy
  3. 然后我们为 IHubCallerClientsIClientProxy 创建一个 mock 对象
  4. 在第 22 行,我们设置 mock 对象,以便在调用 All 属性时,返回 IClientProxy mock 对象的实例。
  5. 然后我们创建一个 SimpleHub 并告诉它使用我们的 mock 对象进行 Clients 委托。现在我们对流程拥有完全的控制权。
  6. 我们调用 SimpleHub.Welcome,这会启动将消息发送到已连接客户端的整个过程。
  7. 在第 35 行,我们检查 IHubCallerClients 的 mock 对象确实被使用了,并且只被调用了一次。
  8. 第 37 行更具体
    • 首先,我们正在检查对 SendCoreAsync 的调用,因为我们在 hub 中使用的 SendAsync 方法实际上是一个扩展方法,它只是将参数包装到数组中并将其发送到 SendCoreAsync
    • 我们检查在客户端实际要调用的方法确实命名为 welcome
    • 然后我们检查发送的消息不是 null(作为一个*and*子句,如果它是null,它会短路),它有一个Length为 1(记住,早些时候消息被包装在一个额外的数组中),并且该集合的第一个元素确实是一个包含 3 个项目(我们的消息)的对象数组。
    • 由于 Moq 无法验证可选参数,我们还必须为 CancelationToken 提供默认值。
    • 最后,我们检查消息只发送了一次。

至此,我们已经测试了我们的 SignalR hub 确实按预期工作。使用这种方法,在一个单独的项目中,我还可以细致地测试所有传入的内容,包括消息只发送给一个特定客户端的情况。

这就是我们关于测试 ASP.NET Core 2.1.0 的 SignalR 的帖子。
希望您喜欢,下次再见,

© . All rights reserved.