Search code examples
c#asp.net-coresignalrxunit

XUnit Testing SignalRHub with Moq, both client and server side, unable to create with successful moq and unit test


I have a simple Signalr collection of Hubs responsible for sending notifications across the application which mostly consist of user names and messages, I have been trying to create a Xunit test script with unit test which are capable of testing both the server-side Hub method and the Client side Hub method in one unit test for each hub connection, I'm having no luck and most of what im reading online seem to be dated and not effective, I'm struggling with null references and creating something which doesn't really on the use of mocking an object.......Nearly all the hubs are just sending strings for now, does anyone have any experience or solutions when unit testing SignalR using moqs ?, please see code below for example of how the hubs will work in general...

server hub

public async Task SendMessage(string userName, string message)
 {
     await Clients.All.SendAsync("OnMessageReceived", userName, message);
 }

client hub

connection.on("OnMessageReceived", function (userName, message) {
    console.log("this is the user Name =>", userName)
    console.log("this is the user Message =>", message)
})

Test Scripts using xunit testing below, ive tried many different ways to make a simple moq and unit test to test both hub above, but can not get anything to test or work successfully. Ive looked at the MS docs and tried a few different scripts online but cannot get anything to work as one unit test to test both hub connections in one test. Need to set something up for a void method I think but unsure how.

[Fact]
public async Task HubsAreMockableVia()
{
    //.........Test Mock connection works and is verified, but uncertain this is a good test
    //var mock = new Mock<CreateConnectionHub>();
    //mock.Object.SendMessage("TestUser", "TestMessage");
    //mock.Verify();

   
    Mock<IHubCallerClients> mockClients = new Mock<IHubCallerClients>();
    Mock<IClientProxy> mockClientProxy = new Mock<IClientProxy>();

    mockClients.Setup(clients => clients.All).Returns(mockClientProxy.Object);


  
    CreateConnectionHub testhub = new CreateConnectionHub()
    {
        Clients = mockClients.Object
    };


    await testhub.SendMessage("hello","user");
      mockClients.Verify(clients => clients.All, Times.Once);

      mockClientProxy.Verify(
      clientProxy => clientProxy.SendAsync(
          "OnMessageReceived",

         It.IsAny<string>(),
         It.IsAny<string>(),

          default(CancellationToken)),
      Times.Once);

}

Returns: Message:  System.NotSupportedException : Unsupported expression: clientProxy => clientProxy.SendAsync("OnMessageReceived", It.IsAny(), It.IsAny(), CancellationToken) Extension methods (here: ClientProxyExtensions.SendAsync) may not be used in setup / verification expressions.

Ive tried to rework this a few ways but not found a work around, thank you for your time.


Solution

  • The following code fix runs a clean test which passes; it allows for NUnit to check if testhub sends the message and is receiving the two string variable as required.

    await testhub.SendMessage("hello","user");
      mockClients.Verify(clients => clients.All, Times.Once);
    
      mockClientProxy.Verify(
      clientProxy => clientProxy.SendAsync(
          "OnMessageReceived",
    
            It.Is<object[]>(o => o != null && o.Length == 2),
    
          default(CancellationToken)),
      Times.Once);