0
votes

I am using SignalR in my ASP.NET Core (3.1) Web API application, and everything is working just fine.

However, I need a way to create an instance of the hub context in my unit tests, (since unit tests don't support DI) and I haven't found anything useful in the documentation.

For example, I have this manager class:

public MyManager(IHubContext<ChatHub> hubContext)
{
    this.hubContext = hubContext;
    ...
}

which I should instantiate in my unit tests, but don't know how without the hub context.

Also, I don't actually need to mock SignalR calls, it doesn't matter if they don't work in the tests. I just want my tests not to fail.

1

1 Answers

0
votes

A example how to mock the Context with a interface:

/// <summary>
/// The mock context.
/// </summary>
private static readonly Mock<IHubContext<NotificationsHub, INotificationsHub>> mockHubContext = new Mock<IHubContext<NotificationsHub, INotificationsHub>>();

Then you can setup it like:

/// <summary>
/// Builds the notifications hub.
/// </summary>
/// <returns>NotificationsHub.</returns>
private static Mock<IHubContext<NotificationsHub, INotificationsHub>> BuildNotificationsHub()
{
    // Mock

    Mock<INotificationsHub> hubClientsMock = new Mock<INotificationsHub>();

    // Setup

    mockHubContext.Setup(mock => mock.Clients.Group(It.IsAny<string>())).Returns(hubClientsMock.Object);
    mockHubContext.Setup(mock => mock.Clients.Group(It.Is<string>(group => group == "HubException"))).Throws(new HubException());
    mockHubContext.Setup(mock => mock.Groups).Returns(mockGroupManager.Object);

    // Return the manager

    return mockHubContext;
}

And what microsoft recomends is that if you want inject the context, it would be better if you injected it using DI and not in the constructor like:

private IHubContext<NotificationsHub, INotificationsHub> NotificationsHub
{
    get
    {
        return this.serviceProvider.GetRequiredService<IHubContext<NotificationsHub, INotificationsHub>>();
    }
}