2017-06-09 49 views
2

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

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調用。

MockTest

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

任何幫助表示讚賞,完成/更正這個單元測試。

回答

3

需要重新設計。基地ApiController緊密耦合到集線器上下文的靜態訪問者。這需要重構到自己的服務中,以便通過構造函數注入來獲得更大的靈活性。

​​

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

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容器的新服務,以便它可以注入到依賴控制器。

隨着重新設計,基本控制器可以一起拆除,並直接使用中樞供應商。這是假設沒有任何其他理由擁有基本控制器。