19

我想在 SignalR 中测试我的集线器,最好的方法是什么?

到目前为止我想到的可能的解决方案:

  • 创建一个可测试的 Hub
  • 分离类的抽象逻辑
  • Selenium(想测试更小的单元)
  • 还是忽略了一些 SignalR 测试功能

目前使用 SignalR 0.4 和 NUnit 作为测试框架。

4

6 回答 6

8

链接显示如何使用 Moq 对 SignalR 集线器方法进行单元测试。您模拟存储库、客户端、上下文和调用者。这是来自该站点的代码,我做了一些小改动以使其与最新的 SignalR 一起使用:

public class TestableChatHub : ChatHub  
{  
 public Mock<IChatRepository> MockChatRepository { get; private set; }

 public TestableChatHub(Mock<IChatRepository> mockChatRepository)  
   : base(mockChatRepository.Object)  
 {
   const string connectionId = "1234";  
   const string hubName = "Chat";  
   var mockConnection = new Mock<IConnection>();  
   var mockUser = new Mock<IPrincipal>();  
   var mockCookies = new Mock<IRequestCookieCollection>();

   var mockRequest = new Mock<IRequest>();  
   mockRequest.Setup(r => r.User).Returns(mockUser.Object);  
   mockRequest.Setup(r => r.Cookies).Returns(mockCookies.Object);

   Clients = new ClientProxy(mockConnection.Object, hubName);  
   Context = new HubCallerContext(mockRequest.Object, connectionId);

   var trackingDictionary = new TrackingDictionary();  
   Caller = new StatefulSignalProxy(
        mockConnection.Object, connectionId, hubName, trackingDictionary);  
 }  
} 

然后该站点显示您可以使用这个可测试的集线器来编写单元测试:

   [TestClass]  
   public class ChatHubTests  
   {  
     private TestableChatHub _hub;

     public void SetUpTests()  
     {  
       _hub = GetTestableChatHub();  
     }

     [Test]  
     public void ExampleTest()  
     {  
       SetUpTests();
       const string message = "test";  
       const string connectionId = "1234";

       var result = _hub.Send(message);

       _hub.MockChatRepository.Verify(r => r.SaveMessage(message, connectionId));
       Assert.IsTrue(result);  
     }

     private TestableChatHub GetTestableChatHub()  
     {  
       var mockRepository = new Mock<IChatRepository>();  
       mockRepository.Setup(m => m.SaveMessage(
            It.IsAny<string>(), It.IsAny<string())).Returns(true);  
       return new TestableChatHub(mockRepository);  
     }  
   }  
于 2012-10-04T01:52:40.850 回答
5

使用几个巧妙的技巧来创建单元测试 SignalR 集线器非常简单。需要注意的一件事是 SignalR 使用dynamic了您的模拟框架可能不支持的类(我使用NSubstitute)。

public class ProjectsHub: Hub
{
   public void AddProject(string id)
   {
      Clients.All.AddProject(id);
   }
}

[TestFixture]
public class ProjectsHubTests
{
    // Operations that clients might receive
    // This interface is in place in order to mock the
    // dynamic object used in SignalR
    public interface ISignals
    {
        void AddProject(string id);
    }

    [Test]
    public void AddProject_Broadcasts()
    {
        // Arrange
        ProjectsHub hub = new ProjectsHub();
        IHubCallerConnectionContext clients = 
                Substitute.For<IHubCallerConnectionContext>();
        ISignals signals = Substitute.For<ISignals>();
        SubstituteExtensions.Returns(clients.All, signals);
        hub.Clients = clients;

        // Act
        hub.AddProject("id");

        // Assert
        signals.Received(1).AddProject("id");
    }
}

重写它以使用例如 Moq 应该非常简单。

于 2014-03-25T10:48:29.757 回答
4

这个问题是很久以前的问题了,但我还是会尽力回答。

如果您的实际集线器类中有很多逻辑,那么将逻辑抽象到一个单独的类肯定是​​有意义的。我为我的 SignalR 驱动的多人演示做了同样的事情。集线器类本身的唯一行为是与消息传递相关的行为。所有进一步的行动都应授权。

注意:这与 ASP .NET MVC 中的控制器设计指南非常相似:保持控制器小型化并委派实际工作。

如果您希望与 SignalR 的集成测试实际做一些工作,selenium webdriver 将是一个不错的选择。但是您可能需要进行一些调整才能使 SignalR 消息传递在测试环境中完美运行。在谷歌上搜索“signalr selenium”(不带引号)以开始正确的轨道。

一些关于 SignalR 自动化测试的博文 =>这里这里

于 2012-06-10T09:25:37.273 回答
2

使用 SignalR 2.0,您可以这样做:

// Arrange
var hub = new CodeInteractivePreviewHub();
var mockClients = new Mock<IHubCallerConnectionContext<dynamic>>();
hub.Clients = mockClients.Object;
dynamic all = new ExpandoObject();
mockClients.Setup(m => m.All).Returns((ExpandoObject)all);

// Act
var allSourceCodes = hub.InitiateCommunication(); //Change this line to your Hub's method 

// Assert
Assert.IsNotNull(allSourceCodes);
于 2015-01-30T23:33:54.003 回答
0

这是 Iarsm 答案的修改版本,可与 XUnit 和 MOQ 一起使用。

using Microsoft.AspNet.SignalR;
using Microsoft.AspNet.SignalR.Hubs;
using Moq;
using Xunit;

namespace TestLibrary {
public class ProjectsHub : Hub {
    public void AddProject(string id) {
        Clients.All.AddProject(id);
    }
}

public class ProjectsHubTests {
    // Operations that clients might receive
    // This interface is in place in order to mock the
    // dynamic object used in SignalR
    public interface ISignals {
        void AddProject(string id);
    }

    [Fact]
    public void AddProject_Broadcasts() {
        // Arrange
        ProjectsHub hub = new ProjectsHub();
        var clients = new Mock<IHubCallerConnectionContext<dynamic>>();
        var signals = new Mock<ISignals>();
        hub.Clients = clients.Object;

        signals.Setup(m => m.AddProject(It.Is<string>(s => s == "id"))).Verifiable();
        clients.Setup(m => m.All).Returns(signals.Object);

        // Act
        hub.AddProject("id");

        // Assert
        signals.VerifyAll();
    }
}

}

于 2014-10-28T12:52:21.037 回答
0

我的界面不在测试项目中,但这是我使用 NUnit 和 Moq 的方式。

using Microsoft.AspNetCore.SignalR;
using Moq;
using NUnit.Framework;

namespace TestLibrary
{
    // Operations that clients might receive
    // This interface is in place in order to mock the
    // dynamic object used in SignalR
    public interface ISignals
    {
        void AddProject(string id);
    }

    public class ProjectsHub : Hub<ISignals>
    {
        public void AddProject(string id)
        {
            Clients.All.AddProject(id);
        }
    }

    public class ProjectsHubTests
    {

        [Test]
        public void AddProject_Broadcasts()
        {
            // Arrange
            ProjectsHub hub = new ProjectsHub();
            var clients = new Mock<IHubCallerClients<ISignals>>();
            var signals = new Mock<ISignals>();
            hub.Clients = clients.Object;

            signals.Setup(m => m.AddProject(It.Is<string>(s => s == "id"))).Verifiable();
            clients.Setup(m => m.All).Returns(signals.Object);

            // Act
            hub.AddProject("id");

            // Assert
            signals.VerifyAll();
        }
    }
}

于 2021-01-09T16:51:16.320 回答