gpt4 book ai didi

c# - 模拟 ApiController SignalR 广播

转载 作者:行者123 更新时间:2023-12-04 00:00:30 25 4
gpt4 key购买 nike

我正在尝试模拟 ApiController(WebApi) 中存在的 SignalR 广播,但无法完成测试用例,下面是我的代码

信号RHub

public class HubServer : Hub { }

ApiControllerWithHub

public abstract class ApiControllerWithHubController<THub> : ApiController where THub : IHub
{
Lazy<IHubContext> hub = new Lazy<IHubContext>(() => GlobalHost.ConnectionManager.GetHubContext<THub>());

protected IHubContext Hub
{
get { return hub.Value; }
}
}

Controller (模拟方法)

public class NotificationController : ApiControllerWithHubController<HubServer>
{
[HttpPost]
public HttpResponseMessage SendNotification(NotificationInput notification)
{
Hub.Clients.Group("GroupName").BroadcastCustomerGreeting("notification");
}
}

我正在 Mock SignalR Post 的帮助下编写以下单元测试,我被困在这里,因为这是来自 Controller 而不是来自 SignalR Hub 的 SignalR 调用。

模拟测试

public interface IClientContract
{
void BroadcastCustomerGreeting(string message);
}

[TestMethod]
public void SendNotificationTest()
{
NotificationInput notificationInput = new NotificationInput();
notificationInput.CId = "CUST001";
notificationInput.CName = "Toney";

// Arrange
var mockClients = new Mock<IHubConnectionContext<dynamic>>();
var mockGroups = new Mock<IClientContract>();

// Act.
mockGroups.Setup(_ => _.BroadcastCustomerGreeting("notification")).Verifiable();
mockClients.Setup(_ => _.Group("GroupName")).Returns(mockGroups.Object);

// I'm stuck here
var controller = new NotificationController();

// Act
HttpResponseMessage actionResult = controller.SendNotification(notificationInput);
}

感谢任何有助于完成/更正此单元测试的帮助。

最佳答案

需要重新设计。基本 ApiController 与集线器上下文的静态访问器紧密耦合。这需要重构到它自己的服务中,以通过构造函数注入(inject)实现更大的灵 active 。

public interface IHubContextProvider {
IHubContext Hub { get; }
}

public class HubContextProvider<THub> : IHubContextProvider where THub : IHub {
Lazy<IHubContext> hub = new Lazy<IHubContext>(() => GlobalHost.ConnectionManager.GetHubContext<THub>());
public IHubContext Hub {
get { return hub.Value; }
}
}

现在需要重构 Controller 以显式公开其依赖项。

public abstract class ApiControllerWithHubController<THub> : ApiController where THub : IHub {

private readonly IHubContext hub;

public ApiControllerWithHubController(IHubContextProvider context) {
this.hub = context.Hub;
}

protected IHubContext Hub {
get { return hub; }
}
}


public class NotificationController : ApiControllerWithHubController<HubServer> {

public NotificationController(IHubContextProvider context)
: base(context) {

}

[HttpPost]
public IHttpActionResult SendNotification(NotificationInput notification) {
Hub.Clients.Group("GroupName").BroadcastCustomerGreeting("notification");
return Ok();
}
}

现在可以使用必要的依赖项模拟来进行测试。

[TestMethod]
public void _SendNotificationTest() {

// Arrange
var notificationInput = new NotificationInput();
notificationInput.CId = "CUST001";
notificationInput.CName = "Toney";
var groupName = "GroupName";
var message = "notification";

var mockGroups = new Mock<IClientContract>();
mockGroups.Setup(_ => _.BroadcastCustomerGreeting(message)).Verifiable();

var mockClients = new Mock<IHubConnectionContext<dynamic>>();
mockClients.Setup(_ => _.Group(groupName)).Returns(mockGroups.Object).Verifiable();

var mockHub = new Mock<IHubContext>();
mockHub.Setup(_ => _.Clients).Returns(mockClients.Object).Verifiable();

var mockHubProvider = new Mock<IHubContextProvider>();
mockHubProvider.Setup(_ => _.Hub).Returns(mockHub.Object);

var controller = new NotificationController(mockHubProvider.Object);

// Act
var actionResult = controller.SendNotification(notificationInput);

//Assert
mockClients.Verify();
mockGroups.Verify();
mockHub.Verify();
}

只需确保向 DI 容器注册新服务,以便它可以注入(inject)依赖的 Controller 。

通过重新设计,可以将基本 Controller 一起移除,并直接使用集线器提供程序。这是假设没有任何其他原因需要基本 Controller 。

关于c# - 模拟 ApiController SignalR 广播,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44457319/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com