【问题标题】:How should I mock SignalR HubContext in Controller for Unit Testing?我应该如何在 Controller 中模拟 SignalR HubContext 以进行单元测试?
【发布时间】:2014-04-24 14:35:01
【问题描述】:

我在 MVC5 项目中使用 SignalR。我在控制器中这样调用:

private Microsoft.AspNet.SignalR.IHubContext blogHubContext = Microsoft.AspNet.SignalR.GlobalHost.ConnectionManager.GetHubContext<BlogHub>();
blogHubContext.Clients.All.addNewBlogToPage(RenderPartialViewToString("Blog", model));

我正在尝试对此控制器中的操作进行单元测试。在我添加 SignalR 功能之前,单元测试工作正常。现在我正在尝试研究如何模拟 HubContext。我有两种可能。

  1. 我在构造函数中设置了集线器,所以我有如下内容:

    private Microsoft.AspNet.SignalR.IHubContext blogHubContext;
    public BlogController(Microsoft.AspNet.SignalR.IHubContext topicHub = null){
         blogHubContext = (blogHub != null) ? blogHub : Microsoft.AspNet.SignalR.GlobalHost.ConnectionManager.GetHubContext<BlogHub>();
    }
    

    然后,当我在单元测试中创建它时,我可以以某种方式模拟 HubContext 并将其发送到控制器。到目前为止,我只有这个:

    Mock<IHubContext> blogHub = new Mock<IHubContext>();
    

    (注意:我已经简化了所有内容,只专注于 SignalR 方面。控制器等中也使用了存储库)

  2. 另外,我考虑创建另一个类来包装集线器,然后只调用其中的函数来调用集线器。我认为这对我的单元测试来说更容易模拟,但不确定这是否是个好主意。

方向赞赏。或者两者都是可以接受的前进方式?谢谢。

【问题讨论】:

  • 我更喜欢第一个选项,因为您不需要另外一层不添加任何功能的包装类。
  • @AD.Net 谢谢。在这种情况下,任何想法我可以如何去模拟我正在使用的功能的集线器。我一直在努力弄清楚如何去做,这让我想到了第二种选择。
  • 你对 mocking 熟悉吗?模拟信号器集线器似乎与模拟其他任何东西差不多。
  • @BenAaronson 由于 addNewBlogToPage 函数实际上是一个由 SignalR 调用的 JS 函数,我不知道如何去模拟它。但是,现在遵循 AD.Net 的建议,可能会将事情重新设计成更好的结构。
  • @AndrewPolland,js 函数将基于您的 .net 代码,因此对于 js 代理生成应该没什么大不了的。

标签: c# unit-testing signalr moq asp.net-mvc-5


【解决方案1】:

更新,请看这段代码,我基于默认的 MVC 模板。不需要包装类。

public class HomeController : Controller
{
   private readonly IHomeHub _hub;

   public HomeController(IHomeHub hub)
   {
      _hub = hub;
   }

   public ActionResult Index()
   {
      _hub.Hello();
      return View();
   }
}

public interface IHomeHub
{
   void Hello();
}

public class HomeHub : Hub, IHomeHub
{
   public void Hello()
   {
      Clients.All.hello();
   }
}

对于单元测试:

[TestMethod]
public void Index()
{
   var mockHub = new Mock<IHomeHub>();
   // Arrange
   HomeController controller = new HomeController(mockHub.Object);

   // Act
   ViewResult result = controller.Index() as ViewResult;

   // Assert
   Assert.IsNotNull(result);
   mockHub.Verify(h=>h.Hello(), Times.Once);
}

【讨论】:

  • 这看起来真的很好。但我无法让它工作,因为如果它是静态的,只能从集线器(控制器内)调用一个函数,而从接口实现时它不能。所以无论如何我的理解。
  • 抱歉不清楚,方法 Hello 在 Hub 类上不是静态的,您可以从控制器调用它。
  • 对不起,部分问题是我的结局。正如我所想的那样不需要静态。但是,当从控制器调用方法 Hello 时,不能像您那样调用客户端。它会产生以下错误:不支持使用不是由 HubPipeline 创建的 Hub 实例。
  • 我已对您的答案进行了编辑,以便它可以正常工作。希望你同意。
  • 抱歉,编辑被拒绝。但本质上不是 Clients.All.hello();我不得不使用 var hubContext = GlobalHost.ConnectionManager.GetHubContext(); hubContext.Clients.All.hello();
猜你喜欢
  • 1970-01-01
  • 2018-06-29
  • 2021-11-22
  • 2013-11-18
  • 1970-01-01
  • 1970-01-01
  • 2013-03-25
  • 2016-09-18
  • 1970-01-01
相关资源
最近更新 更多