Course contentsShow
← C#
Lesson 1471 of 1,90813. Real-time Communication with SignalRFree lesson

Unit Testing Hub Methods

Mock HubCallerContext and HubClients to verify business logic without requiring a network socket.

In this lesson, you will learn how to isolate and verify your SignalR Hub logic by mocking the HubCallerContext and IHubCallerClients interfaces to avoid the overhead of a real network socket.

Testing SignalR hubs directly can be cumbersome if you attempt to spin up an entire server instance. Instead, because SignalR hubs are designed to be testable components, we can treat them like standard classes by injecting mock implementations of their dependencies. The two critical dependencies are HubCallerContext (which identifies the user and connection) and IHubCallerClients (which handles the outgoing messages).

By using a mocking library like Moq, we can simulate a connection and verify that our hub triggers the correct client-side methods without actually sending data over the wire.

Practical Implementation

Consider a hub method that sends a "Notify" message to a specific user. We don't want to test the transport layer; we want to test the orchestration.

[Fact]
public async Task SendMessage_ShouldCallClientMethod()
{
    // Arrange
    var mockClients = new Mock<IHubCallerClients>();
    var mockClientProxy = new Mock<IClientProxy>();
    
    // Setup the mock to capture the call
    mockClients.Setup(clients => clients.Caller).Returns(mockClientProxy.Object);
    
    var hub = new MyHub {
        Clients = mockClients.Object,
        Context = new Mock<HubCallerContext>().Object
    };

    // Act
    await hub.SendMessage("Hello World");

    // Assert
    mockClientProxy.Verify(
        client => client.SendCoreAsync("ReceiveMessage", It.IsAny<object[]>(), default),
        Times.Once);
}

In this example, we aren't testing SignalR’s internals; we are verifying that when SendMessage is executed, our logic correctly invokes ReceiveMessage on the caller. By mocking the IClientProxy, we can inspect the arguments passed to it or verify that the method was triggered exactly once. This allows you to write fast, deterministic unit tests that ensure your business rules remain intact as your hub grows in complexity, all while keeping your test suite lightweight.

Key Takeaway: By mocking HubCallerContext and IHubCallerClients, you transform complex integration-heavy SignalR scenarios into lightweight, reliable unit tests that verify business logic in total isolation.