Reputation: 1065
Is is possible to initialize HubConnection
from Microsoft.AspNetCore.TestHost.TestServer
?
The example below throws HttpRequestException
(Not Found) exception at await hubConnection.StartAsync();
using System;
using System.Threading.Tasks;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.SignalR.Client;
using Microsoft.AspNetCore.TestHost;
using Xunit;
namespace FunctionalTests
{
public class PubSubScenarios
{
[Fact]
public async Task SignalRHubTest_Foo()
{
var webHostBuilder = WebHost.CreateDefaultBuilder().UseStartup<Startup>();
using (var testServer = new TestServer(webHostBuilder))
{
var hubConnection = await StartConnectionAsync(testServer.BaseAddress);
}
}
private static async Task<HubConnection> StartConnectionAsync(Uri baseUri)
{
var hubConnection = new HubConnectionBuilder()
.WithUrl($"http://{baseUri.Host}/fooHub")
.WithConsoleLogger()
.Build();
await hubConnection.StartAsync();
return hubConnection;
}
}
}
Upvotes: 4
Views: 2929
Reputation: 310
To make this work with Websockets as transport,
public class PingComponentTest
{
private static WebApplicationFactory<Program> _testWebApplicationFactory = null!;
private static HubConnection _yourWhateverHubConnection = null!;
[ClassInitialize]
public static void ClassInitialize(TestContext context)
{
_testWebApplicationFactory = new TestWebApplicationFactory<Program>();
_yourWhateverHubConnection = new HubConnectionBuilder()
.WithUrl($"{_testWebApplicationFactory.Server.BaseAddress}YourWhateverHub", options =>
{
options.Transports = HttpTransportType.WebSockets;
options.HttpMessageHandlerFactory = _ => _testWebApplicationFactory.Server.CreateHandler();
options.WebSocketFactory = (context, cancellationToken) =>
{
var webSocketClient = _testWebApplicationFactory.Server.CreateWebSocketClient();
var webSocketTask = webSocketClient.ConnectAsync(context.Uri, cancellationToken);
return new ValueTask<WebSocket>(webSocketTask);
};
})
.ConfigureLogging(logging =>
{
// See more messages from test server in output to better understand context
logging.AddFilter("Microsoft.AspNetCore.SignalR", LogLevel.Debug);
logging.AddFilter("Microsoft.AspNetCore.Http.Connections", LogLevel.Debug);
})
.Build();
}
[ClassCleanup]
public static void ClassCleanup()
{
_yourWhateverHubConnection.DisposeAsync().AsTask().Wait();
_testWebApplicationFactory.Dispose();
}
[TestInitialize]
public void TestInitialize()
{
_yourWhateverHubConnection.StartAsync().Wait();
}
[TestCleanup]
public void TestCleanup()
{
_yourWhateverHubConnection.StopAsync().Wait();
}
[TestMethod]
public async Task InvokePing_Should_ReturnPong()
{
var invokePingResult = await _yourWhateverHubConnection.InvokeAsync<string>(nameof(YourWhateverHub.InvokePing));
Assert.IsNotNull(invokePingResult);
Assert.AreEqual(invokePingResult, "pong");
}
}
And Hub for this shall be something like
public class YourWhateverHub : Hub
{
public Task<string> InvokePing()
{
return Task.FromResult("pong");
}
}
Solution inspired from aspnetcore issue #11888
Upvotes: 1
Reputation: 38764
You need to call testServer.CreateHandler() and pass the HttpMessageHandler to WithMessageHandler:
[Fact]
public async Task SignalRHubTest_Foo()
{
var webHostBuilder = WebHost.CreateDefaultBuilder().UseStartup<Startup>();
using (var testServer = new TestServer(webHostBuilder))
{
var hubConnection = await StartConnectionAsync(testServer.CreateHandler());
}
}
private static async Task<HubConnection> StartConnectionAsync(HttpMessageHandler handler)
{
var hubConnection = new HubConnectionBuilder()
.WithUrl($"http://test/fooHub", options =>
{
options.Transports = HttpTransportType.LongPolling;
options.HttpMessageHandlerFactory = _ => handler;
})
.Build();
await hubConnection.StartAsync();
return hubConnection;
}
This won't work for websockets though (I opened an issue for this here https://github.com/aspnet/SignalR/issues/1595
Upvotes: 6