簡體   English   中英

模擬ApiController SignalR廣播

[英]Mocking ApiController SignalR broadcasting

我試圖嘲弄SignalR廣播目前在ApiController (的WebAPI),但無法完成測試的情況下,下面是我的代碼

SignalRHub

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; }
    }
}

控制器(模擬方法)

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

我正在借助Mock SignalR Post編寫以下單元測試,我被困在這里 ,因為這是來自控制器而不是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緊密耦合到集線器上下文的靜態訪問器。 這需要重構為它自己的服務,以通過構造函數注入獲得更大的靈活性。

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; }
    }
}

現在需要重構控制器以顯式公開其依賴關系。

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容器中注冊新服務,以便可以將其注入到相關的控制器中。

通過重新設計,可以一起刪除基本控制器,並且可以直接使用集線器提供程序。 這是假設沒有其他原因擁有基本控制器。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM