Net Core - Интеграционный тест - TestServer - реальное http-соединение - PullRequest
0 голосов
/ 08 ноября 2019

У нас есть несколько .NET Core Microservices / API, и мы хотим провести несколько интеграционных тестов. Итак, мы следовали инструкциям, и они отлично работают, за исключением одной ситуации.

Представьте, что у меня есть 3 API, так что 3 экземпляра "TestServer", каждый из которых имеет свой собственный HttpClient для подключения!

Я показываю способ создания TestServer:

    private TestServer SetupAPI<TStartup>(string path, string uri) where TStartup : class
    {
        string rootPath = Path.Join(_rootPath, "path");

        var hostBuilder = WebHost.CreateDefaultBuilder()
            .UseUrls(uri)
            .UseIISIntegration()
            //.ConfigureServices(services => services.AddSecurityHeaders())
            .UseContentRoot(rootPath)
            .UseEnvironment("Development")
            .ConfigureAppConfiguration(cb =>
            {
                cb.AddJsonFile("appsettings.json", optional: false)
                //.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
                .AddEnvironmentVariables();
            })
            .UseStartup<TStartup>();

        TestServer server = new TestServer(hostBuilder);
        server.BaseAddress = new Uri(uri);

        return server;
    }

Я показываю, как я создаю HttpClient:

        client = ArtistsServer.CreateClient();
        client.BaseAddress = new Uri("http://localhost:5000");
        client.DefaultRequestHeaders.Accept.Clear();
        client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));

Он работает отлично, но когда я пытаюсь создать новый HttpClient, которыйКстати, это не удалось: HttpClient httpClient = new HttpClient ();httpClient.BaseAddress = new Uri ("http://localhost:5000");

Настоящая проблема заключается в том, что некоторые микросервисы таким образом создают свой собственный HttpClient для связи с другим API! Они настраиваются через файл appsettings.json и пытаютсяподключитесь к обычному и реальному http-серверу, а не к «TestServer»!

У вас есть идеи, чтобы решить эту проблему?

Спасибо

1 Ответ

0 голосов
/ 08 ноября 2019

Это не так, как это работает. Интеграционный тест - это тест набора компонентов, составляющих приложение single . Если вы тестируете Api1, вы не раскручиваете экземпляры Api2 и Api3;Вы издеваетесь над ними так, чтобы они вели себя известным и предсказуемым образом. Если вы использовали реальные экземпляры, даже test instance, то сбой в Api2 может привести к сбою вашего теста Api1, даже если в Api1 нет ничего плохого. Итак, Api1 может обмениваться даннымидля Api2 вам потребуется HttpClient для отправки запросов. Это HttpClient должно быть предоставлено IHttpClientFactory и введено в класс обслуживания, зарегистрированный как типизированный клиент. В этом классе обслуживания вы бы добавили методы, соответствующие вызовам API. Для тестируемости этот класс обслуживания должен реализовывать интерфейс, и вам следует вводить интерфейс всякий раз, когда вам нужно работать с этим API. Это выглядит примерно так:

public interface IApi2Service
{
    Task<Foo> GetFooByIdAsync(int id);
}

public class Api2Service : IApi2Service
{
    private readonly HttpClient _client;

    public Api2Service(HttpClient client)
    {
        _client = client;
    }

    public async Task<Foo> GetFooByIdAsync(int id)
    {
        // use _client to make the API call
    }
}

Затем в Startup.ConfigureServices:

services.AddHttpClient<IApi2Service, Api2Service>(c =>
{
    c.BaseAddress = new Uri(Configuration["Api2BaseAddress"]);
});

И, наконец, в классе (возможно, контроллере) в Api1, где вам нужно взаимодействовать с Api2, вы делаете:

public class SomeApi1Controller : ControllerBase
{
    private readonly IApi2Service _api2Service;

    public SomeApi1Controller(IApi2Service api2Service)
    {
        _api2Service = api2Service;
    }

    public async Task<IActionResult> SomeAction()
    {
        var foo = await _api2Service.GetFooByIdAsync(1);
    }
}

Теперь, когда ваш код правильно настроен, вы просто добавите в тестовую реализацию Api2Service и заглушите метод GetFooByIdAsync, чтобы просто вернуть тест Foo экземпляр, вместо на самом деле совершение вызова Api2 через HttpClient. Таким образом, вы точно знаете, что будет возвращено, и сможете соответствующим образом спроектировать свой тест, возвращая различные типы Foo в зависимости от того, что вы тестируете.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...