Testing SignalR in ASP.NET Core with Integration Tests
As promised in my last post, I’m following up on how to test your SignalR hubs in an end to end manner using TestServer. This post is a build up on my last post so if you haven’t read it, go do so now!
Setup
I have a Hub named ChatHub that has the following method:
1 2 3 4 |
public async Task SendMessage(string user, string message) { await Clients.All.SendAsync("OnMessageReceived", user,message); } |
My clients all are connected to (listen to) a method to receive messages called OnMessageReceived.
Tests
In my test class, I created a method to help me start my connection. If you plan on testing multiple hubs, you may want to move this method to a helper class.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
private static async Task<HubConnection> StartConnectionAsync(HttpMessageHandler handler, string hubName) { var hubConnection = new HubConnectionBuilder() .WithUrl($"ws://localhost/hubs/{hubName}", o => { o.HttpMessageHandlerFactory = _ => handler; }) .Build(); await hubConnection.StartAsync(); return hubConnection; } |
Dom, my Hubs are protected with a Jwt Token…
No worries, you can pass your Jwt token for SignalR to use using the options of the WithUrl method. Just enrich your options by assigning your token to the AccessTokenProvider property as such: o.AccessTokenProvider = () => Task.FromResult(token);
Show me the code!
Here is what my test method looks like
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
[Fact] public async Task sendMessage_should_send_the_user_and_message_to_all_clients() { // Arrange _factory.CreateClient(); // need to create a client for the server property to be available var server = _factory.Server; var connection = await StartConnectionAsync(server.CreateHandler(), "chat"); connection.Closed += async error => { await Task.Delay(new Random().Next(0, 5) * 1000); await connection.StartAsync(); }; // Act string user = null; string message = null; connection.On<string,string>("OnReceiveMessage", (u, m) => { user = u; message = m; }); await connection.InvokeAsync("SendMessage", "super_user", "Hello World!!"); //Assert user.Should().Be("super_user"); message.Should().Be("Hello World!!"); } |
As you can see, you need to send a message to your hub by invoking the SendMessage method in your ChatHub and then setup the receiver through the On<..> method
As mentioned as a comment in the snippet, you need to create a HttpClient through the factory for the Server property to be available.
Note:
I’m using WebSockets with SignalR here. In case you cannot (as your machine does not support WebSockets), change the uri from
ws://localhost/hubs/{hubName} to
http://localhost/hubs/{hubName}
Happy testing!
2018-11-13: I added a sample of the code in my github repo here