Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
Автор: Крис Росс (Chris Ross)
Промежуточное программное обеспечение можно тестировать в изоляции с использованием TestServer. Оно предоставляет следующие возможности.
- Создайте экземпляр конвейера приложения, содержащего только компоненты, которые необходимо протестировать.
- Отправьте пользовательские запросы для проверки поведения ПО промежуточного слоя.
Преимущества.
- Запросы отправляются в памяти, а не сериализуются по сети.
- Это позволяет избежать дополнительных проблем, таких как управление портами и сертификаты HTTPS.
- Исключения в промежуточном программном обеспечении могут передаваться непосредственно вызывающему тесту.
- Можно настроить структуры данных сервера, например HttpContextнепосредственно в тесте.
Настройка TestServer
В тестовом проекте создайте тест:
Создайте и запустите хост, который использует TestServer.
Добавьте все необходимые службы, которые использует ПО промежуточного слоя.
Добавьте в проект ссылку на пакет NuGet
Microsoft.AspNetCore.TestHost.Настройте конвейер обработки для использования промежуточного программного обеспечения в тесте.
[Fact] public async Task MiddlewareTest_ReturnsNotFoundForRequest() { using var host = await new HostBuilder() .ConfigureWebHost(webBuilder => { webBuilder .UseTestServer() .ConfigureServices(services => { services.AddMyServices(); }) .Configure(app => { app.UseMiddleware<MyMiddleware>(); }); }) .StartAsync(); ... }
Замечание
Рекомендации по добавлению пакетов в приложения .NET см. в статьях в разделе "Установка пакетов и управление пакетами" в рабочем процессе потребления пакетов (документация NuGet). Проверьте правильность версий пакета на сайте NuGet.org.
Отправка запросов с помощью HttpClient
Отправка запроса с помощью HttpClient:
[Fact]
public async Task MiddlewareTest_ReturnsNotFoundForRequest()
{
using var host = await new HostBuilder()
.ConfigureWebHost(webBuilder =>
{
webBuilder
.UseTestServer()
.ConfigureServices(services =>
{
services.AddMyServices();
})
.Configure(app =>
{
app.UseMiddleware<MyMiddleware>();
});
})
.StartAsync();
var response = await host.GetTestClient().GetAsync("/");
...
}
Утверждение результата. Сначала сделайте утверждение, противоположное ожидаемому вами результату. Начальное выполнение с ложным положительным утверждением подтверждает, что тест падает при корректной работе посреднического ПО. Запустите тест и убедитесь, что он завершается ошибкой.
В следующем примере ПО промежуточного слоя должен возвращать код состояния 404 (не найден) при запросе корневой конечной точки. Выполните первый тест с Assert.NotEqual( ... );, который должен завершиться ошибкой:
[Fact]
public async Task MiddlewareTest_ReturnsNotFoundForRequest()
{
using var host = await new HostBuilder()
.ConfigureWebHost(webBuilder =>
{
webBuilder
.UseTestServer()
.ConfigureServices(services =>
{
services.AddMyServices();
})
.Configure(app =>
{
app.UseMiddleware<MyMiddleware>();
});
})
.StartAsync();
var response = await host.GetTestClient().GetAsync("/");
Assert.NotEqual(HttpStatusCode.NotFound, response.StatusCode);
}
Измените утверждение, чтобы протестировать ПО промежуточного слоя в обычных условиях работы. Последний тест использует Assert.Equal( ... );. Запустите тест еще раз, чтобы убедиться, что он проходит.
[Fact]
public async Task MiddlewareTest_ReturnsNotFoundForRequest()
{
using var host = await new HostBuilder()
.ConfigureWebHost(webBuilder =>
{
webBuilder
.UseTestServer()
.ConfigureServices(services =>
{
services.AddMyServices();
})
.Configure(app =>
{
app.UseMiddleware<MyMiddleware>();
});
})
.StartAsync();
var response = await host.GetTestClient().GetAsync("/");
Assert.Equal(HttpStatusCode.NotFound, response.StatusCode);
}
Отправка запросов с помощью HttpContext
Тестовое приложение также может отправлять запрос с помощью SendAsync(Action<HttpContext>, CancellationToken). В следующем примере, когда https://example.com/A/Path/?and=query обрабатывается промежуточным ПО, выполняется несколько проверок.
[Fact]
public async Task TestMiddleware_ExpectedResponse()
{
using var host = await new HostBuilder()
.ConfigureWebHost(webBuilder =>
{
webBuilder
.UseTestServer()
.ConfigureServices(services =>
{
services.AddMyServices();
})
.Configure(app =>
{
app.UseMiddleware<MyMiddleware>();
});
})
.StartAsync();
var server = host.GetTestServer();
server.BaseAddress = new Uri("https://example.com/A/Path/");
var context = await server.SendAsync(c =>
{
c.Request.Method = HttpMethods.Post;
c.Request.Path = "/and/file.txt";
c.Request.QueryString = new QueryString("?and=query");
});
Assert.True(context.RequestAborted.CanBeCanceled);
Assert.Equal(HttpProtocol.Http11, context.Request.Protocol);
Assert.Equal("POST", context.Request.Method);
Assert.Equal("https", context.Request.Scheme);
Assert.Equal("example.com", context.Request.Host.Value);
Assert.Equal("/A/Path", context.Request.PathBase.Value);
Assert.Equal("/and/file.txt", context.Request.Path.Value);
Assert.Equal("?and=query", context.Request.QueryString.Value);
Assert.NotNull(context.Request.Body);
Assert.NotNull(context.Request.Headers);
Assert.NotNull(context.Response.Headers);
Assert.NotNull(context.Response.Body);
Assert.Equal(404, context.Response.StatusCode);
Assert.Null(context.Features.Get<IHttpResponseFeature>().ReasonPhrase);
}
SendAsync позволяет напрямую настроить HttpContext объект, а не использовать абстракции HttpClient. Используется SendAsync для управления структурами, доступными только на сервере, например HttpContext.Items или HttpContext.Features.
Как и в более раннем примере, где тестировалась реакция на ответ 404 - Not Found, проверьте противоположное для каждого Assert утверждения в предыдущем тесте. Проверка подтверждает, что тест завершается ошибкой, если ПО промежуточного слоя работает нормально. После того как вы подтвердили, что ложноположительный тест работает, задайте окончательные Assert инструкции для ожидаемых условий и значений теста. Запустите его еще раз, чтобы убедиться, что тест проходит.
Добавление маршрутов запроса
Дополнительные маршруты можно добавить по конфигурации с помощью теста HttpClient:
[Fact]
public async Task TestWithEndpoint_ExpectedResponse ()
{
using var host = await new HostBuilder()
.ConfigureWebHost(webBuilder =>
{
webBuilder
.UseTestServer()
.ConfigureServices(services =>
{
services.AddRouting();
})
.Configure(app =>
{
app.UseRouting();
app.UseMiddleware<MyMiddleware>();
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/hello", () =>
TypedResults.Text("Hello Tests"));
});
});
})
.StartAsync();
var client = host.GetTestClient();
var response = await client.GetAsync("/hello");
Assert.True(response.IsSuccessStatusCode);
var responseBody = await response.Content.ReadAsStringAsync();
Assert.Equal("Hello Tests", responseBody);
Дополнительные маршруты также можно добавить с помощью подхода server.SendAsync.
Ограничения TestServer
TestServer:
- Был создан для репликации поведения сервера для тестирования ПО промежуточного слоя.
- Не пытается реплицировать все HttpClient поведение.
- Пытается предоставить клиенту доступ к максимальному контролю над сервером и с максимальной видимостью того, что происходит на сервере, как это возможно. Например, он может выбрасывать исключения, которые обычно не выбрасываются
HttpClient, чтобы напрямую взаимодействовать с состоянием сервера. - Не задает некоторые заголовки транспорта по умолчанию, так как они обычно не относятся к ПО промежуточного слоя. Для получения дополнительных сведений см. следующий раздел.
- Игнорирует позицию
Stream, переданную с помощью StreamContent. HttpClient отправляет весь поток из начальной позиции, даже если задано положение. Дополнительные сведения см. здесь на GitHub.
Заголовки Content-Length и Transfer-Encoding
TestServer не задает связанные с транспортом заголовки запроса или ответа, такие как Content-Length или Transfer-Encoding. Приложения должны избегать зависимости от этих заголовков, так как их использование зависит от клиента, сценария и протокола. Если Content-Length и Transfer-Encoding требуется для тестирования определенного сценария, их можно указать в тесте при создании HttpRequestMessage или HttpContext. Дополнительные сведения см. в следующих вопросах GitHub:
ASP.NET Core