【问题标题】:Unittest SignalR Hubs单元测试 SignalR 集线器
【发布时间】:2012-06-03 13:43:05
【问题描述】:

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

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

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

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

【问题讨论】:

    标签: unit-testing testing nunit signalr


    【解决方案1】:

    这个link 展示了如何使用 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);  
         }  
       }  
    

    【讨论】:

    【解决方案2】:

    使用几个巧妙的技巧来创建单元测试 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 和 XUnit 一起使用,作为答案发布。
    【解决方案3】:

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

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

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

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

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

    【讨论】:

    • 我重新检查了链接,它们似乎有效。这可能是该网站的临时问题。
    • 是的,Jasmine(或 Selenium)会起作用。我想知道我们是否可以用 NUnit 测试相同的行为。
    • 链接无效。问题是关于 nunit,而不是 javascript!
    【解决方案4】:

    使用 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);
    

    【讨论】:

      【解决方案5】:

      这是 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();
          }
      }
      

      }

      【讨论】:

        【解决方案6】:

        我的界面不在测试项目中,但这是我使用 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();
                }
            }
        }
        
        

        【讨论】:

          猜你喜欢
          • 2020-03-28
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2022-08-09
          • 2016-07-29
          • 1970-01-01
          相关资源
          最近更新 更多