Как выполнить функциональный тест со страницей сервера Blazor, которая содержит клиентское соединение с концентратором signalR
Забыл о том, как выполнить функциональный тест для страницы сервера Blazor, содержащей соединение с клиентским концентратором signalR.
Пока я пробовал раскрутить
WebApplicationFactory
(WAF) из класса запуска SUT. Затем я копирую необходимые сервисы из WAF в сервисы тестового контекста BUnit.
Проблема возникает, когда страница сервера Blazor пытается подключиться к концентратору signalR, предоставленному WAF. System.Net.Http.HttpRequestException: исключение отказано в соединении (см. Списки ниже). Я думаю, это потому, что WAF не использует сокеты, т.е. предлагает сервер в памяти??
Как другие выполняют тесты для аналогичного сценария с помощью signalR и Blazor?
Тестировать пока
[Fact]
public async Task Test_RendersImage()
{
// initialise BUnit with services from WebApplicationFactory
InitialiseBUnitServices();
// publish an mqtt message to trigger sending event from signalR to Blazor server page
// this is triggering back-end services as expected
await _Server.MqttClient.PublishAsync(CreateMessageFromStream(_Stream));
await Task.Delay(3000);
// request bUnit to render the client page and listen for data from signal R here
// fails to connect to signalR hub here
var cut = RenderComponent<WebApp.Pages.Index>();
// output markup to check that client page rendered the incoming data
_Output.WriteLine($"{cut.Markup}");
// await CompletedTask to allow compilation of this async test stub
await Task.CompletedTask;
}
/// <summary>Create an mqtt message from stream</summary>
private ManagedMqttApplicationMessage CreateMessageFromStream(MemoryStream stream)
{
const string Topic = "shinobi/group/monitor/trigger";
var message = new MqttApplicationMessageBuilder()
.WithTopic(Topic)
.WithPayload(stream.ToArray())
.Build();
return new ManagedMqttApplicationMessageBuilder()
.WithApplicationMessage(message)
.Build();
}
private void InitialiseBUnitServices()
{
// get services from WebApplicationFactory and inject into bUnit
var hubProxyFactory = _Server.Factory.Services.GetRequiredService<IHubProxyFactory>();
var loggerDetectionConverter = _Server.Factory.Services.GetRequiredService<ILogger<MotionDetectionConverter>>();
var loggerIndexPage = _Server.Factory.Services.GetRequiredService<ILogger<WebApp.Pages.Index>>();
var loggerInfoConverter = _Server.Factory.Services.GetRequiredService<ILogger<MotionInfoConverter>>();
var loggerJsonVisitor = _Server.Factory.Services.GetRequiredService<ILogger<JsonVisitor>>();
var loggerRepository = _Server.Factory.Services.GetRequiredService<ILogger<MotionDetectionRepository>>();
var navManager = _Server.Factory.Services.GetRequiredService<NavigationManager>();
var repository = _Server.Factory.Services.GetRequiredService<IMotionDetectionRepository>();
Services.AddSingleton(typeof(IHubProxyFactory), hubProxyFactory);
Services.AddScoped<ILogger<MotionDetectionConverter>>(sp => loggerDetectionConverter);
Services.AddScoped<ILogger<WebApp.Pages.Index>>(sp => loggerIndexPage);
Services.AddScoped<ILogger<MotionInfoConverter>>(sp => loggerInfoConverter);
Services.AddScoped<ILogger<JsonVisitor>>(sp => loggerJsonVisitor);
Services.AddScoped<ILogger<IMotionDetectionRepository>>(sp => loggerRepository);
Services.AddScoped<MockNavigationManager>(sp => new MockNavigationManager());
Services.AddScoped<IMotionDetectionRepository>(sp => repository);
}
Страница сервера Blazor
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
/// <summary>
/// Looks like abstract base class NavigationManager also needs a mock or sub class for unit testing.
/// Cannot resolve RemoteNavigationManager from container, it is an internal class. So for mocking purposes have injected a subclass for bUnit tests.
/// </summary>
var hubUrl = NavigationManager.BaseUri.TrimEnd('/') + "/motionhub";
hubUrl = "http://localhost:5000/motionhub"; // hard code url for now
try
{
/// <summary> Using wrapper to allow unit testing!</summary>
Logger.LogInformation("Index.razor page is performing initial render, connecting to secondary signalR hub");
Logger.LogInformation($"hubUrl is {hubUrl}");
hubConnection = HubConnectionBuilder.Create(
hubUrl,
JsonConvertersFactory.CreateDefaultJsonConverters
(
LoggerMotionDetection,
LoggerMotionInfo,
LoggerJsonVisitor
)
);
hubConnection.On<MotionDetection>("ReceiveMotionDetection", ReceiveMessage);
hubConnection.Closed += CloseHandler;
Logger.LogInformation("Starting HubConnection");
await hubConnection.StartAsync();
Logger.LogInformation("Index Razor Page initialised, listening on signalR hub => " + hubUrl.ToString());
}
catch (Exception e)
{
Logger.LogError(e, "Encountered exception => " + e);
}
}
}
Encountered exception => System.Net.Http.HttpRequestException: Connection refused
---> System.Net.Sockets.SocketException (61): Connection refused
at System.Net.Http.ConnectHelper.ConnectAsync(String host, Int32 port, CancellationToken cancellationToken)
--- End of inner exception stack trace ---
at System.Net.Http.ConnectHelper.ConnectAsync(String host, Int32 port, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage request, Boolean allowHttp2, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.CreateHttp11ConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.GetHttpConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancellationToken)
at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Http.Connections.Client.Internal.AccessTokenHttpMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Http.Connections.Client.Internal.LoggingHttpMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at System.Net.Http.HttpClient.FinishSendAsyncUnbuffered(Task`1 sendTask, HttpRequestMessage request, CancellationTokenSource cts, Boolean disposeCts)
at Microsoft.AspNetCore.Http.Connections.Client.HttpConnection.NegotiateAsync(Uri url, HttpClient httpClient, ILogger logger, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Http.Connections.Client.HttpConnection.GetNegotiationResponseAsync(Uri uri, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Http.Connections.Client.HttpConnection.SelectAndStartTransport(TransferFormat transferFormat, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Http.Connections.Client.HttpConnection.StartAsyncCore(TransferFormat transferFormat, CancellationToken cancellationToken)
at System.Threading.Tasks.ForceAsyncAwaiter.GetResult()
at Microsoft.AspNetCore.Http.Connections.Client.HttpConnection.StartAsync(TransferFormat transferFormat, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Http.Connections.Client.HttpConnectionFactory.ConnectAsync(EndPoint endPoint, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Http.Connections.Client.HttpConnectionFactory.ConnectAsync(EndPoint endPoint, CancellationToken cancellationToken)
at Microsoft.AspNetCore.SignalR.Client.HubConnection.StartAsyncCore(CancellationToken cancellationToken)
at Microsoft.AspNetCore.SignalR.Client.HubConnection.StartAsyncInner(CancellationToken cancellationToken)
at System.Threading.Tasks.ForceAsyncAwaiter.GetResult()
at Microsoft.AspNetCore.SignalR.Client.HubConnection.StartAsync(CancellationToken cancellationToken)
at WebApp.Pages.Index.OnAfterRenderAsync(Boolean firstRender) in /Users/simon/Development/Dotnet/CamFrontEnd/Src/WebApp/Pages/Index.razor.cs:line 167
System.Net.Http.HttpRequestException: Connection refused
---> System.Net.Sockets.SocketException (61): Connection refused
at System.Net.Http.ConnectHelper.ConnectAsync(String host, Int32 port, CancellationToken cancellationToken)
--- End of inner exception stack trace ---
at System.Net.Http.ConnectHelper.ConnectAsync(String host, Int32 port, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.ConnectAsync(HttpRequestMessage request, Boolean allowHttp2, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.CreateHttp11ConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.GetHttpConnectionAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at System.Net.Http.HttpConnectionPool.SendWithRetryAsync(HttpRequestMessage request, Boolean doRequestAuth, CancellationToken cancellationToken)
at System.Net.Http.RedirectHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Http.Connections.Client.Internal.AccessTokenHttpMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Http.Connections.Client.Internal.LoggingHttpMessageHandler.SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
at System.Net.Http.HttpClient.FinishSendAsyncUnbuffered(Task`1 sendTask, HttpRequestMessage request, CancellationTokenSource cts, Boolean disposeCts)
at Microsoft.AspNetCore.Http.Connections.Client.HttpConnection.NegotiateAsync(Uri url, HttpClient httpClient, ILogger logger, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Http.Connections.Client.HttpConnection.GetNegotiationResponseAsync(Uri uri, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Http.Connections.Client.HttpConnection.SelectAndStartTransport(TransferFormat transferFormat, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Http.Connections.Client.HttpConnection.StartAsyncCore(TransferFormat transferFormat, CancellationToken cancellationToken)
at System.Threading.Tasks.ForceAsyncAwaiter.GetResult()
at Microsoft.AspNetCore.Http.Connections.Client.HttpConnection.StartAsync(TransferFormat transferFormat, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Http.Connections.Client.HttpConnectionFactory.ConnectAsync(EndPoint endPoint, CancellationToken cancellationToken)
at Microsoft.AspNetCore.Http.Connections.Client.HttpConnectionFactory.ConnectAsync(EndPoint endPoint, CancellationToken cancellationToken)
at Microsoft.AspNetCore.SignalR.Client.HubConnection.StartAsyncCore(CancellationToken cancellationToken)
at Microsoft.AspNetCore.SignalR.Client.HubConnection.StartAsyncInner(CancellationToken cancellationToken)
at System.Threading.Tasks.ForceAsyncAwaiter.GetResult()
at Microsoft.AspNetCore.SignalR.Client.HubConnection.StartAsync(CancellationToken cancellationToken)