2017-06-09 4 views
2

Ich versuche SignalR Rundfunk in ApiController (WebAPI), aber nicht in der Lage zu vervollständigen Testfall zu verspotten, unten ist mein CodeMocking ApiController SignalR Rundfunk

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

Controller (Methode zum Mock)

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

Ich schreibe folgenden Komponententest mit Hilfe von Mock SignalR Post, ich bin hier fest, weil dies SignalR Anruf vom Controller nicht von SignalR Hub ist.

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

Jede Hilfe zu vervollständigen/korrigieren diese Einheit Test geschätzt.

Antwort

3

Redesign erforderlich. Base ApiController ist eng mit dem statischen Zugriffsmechanismus des Hubkontexts gekoppelt. Dies muss in einen eigenen Service umgewandelt werden, um mehr Flexibilität durch Konstruktorinjektion zu ermöglichen.

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 müssen jetzt refaktorisiert werden, um ihre Abhängigkeiten explizit verfügbar zu machen.

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

Test kann jetzt mit notwendigen Abhängigkeiten ausgeführt werden.

Stellen Sie sicher, dass ein neuer Dienst mit dem DI-Container registriert wird, damit er in abhängige Controller eingespeist werden kann.

Mit dem Redesign kann der Basis-Controller komplett entfernt und der Hub-Provider direkt verwendet werden. Dies setzt voraus, dass es keinen anderen Grund gab, den Basiscontroller zu haben.