Как провести интеграционное тестирование клиентского приложения Asp.Net Core, которое опирается на независимый Asp.Net Core Api - PullRequest
0 голосов
/ 04 июня 2018

У меня есть две системы Asp.Net Core, которые полностью независимы, что означает, что они находятся в разных веб-доменах.Тем не менее, они находятся в одном решении в Visual Studio.Обе системы Asp.Net Core будут размещаться, например, в следующих двух доменах:

https://client -localhost: 8080 и https://api -localhost: 8081

, где клиентское приложение выполняет вызовы на различные маршруты домена Api для получения данных.

У меня нет проблем с выполнением интеграционных тестов (с использованием NUnit) для системы Api, дляпример:

// Integration Test for the Api

[TestFixture]
class IntegrationTestShould
{
    public TestServer GetTestServerInstance()
    {
        return new TestServer(new WebHostBuilder()
            .UseStartup<TestServerStartup>()
            .UseEnvironment("TestInMemoryDb"));
    }

    [Test]
    public async Task ReturnProductDataFromTestInMemoryDb()
    {
        using (var server = GetTestServerInstance())
        {
            var client = server.CreateClient();
            var response = await client.GetAsync("/products"); // equivalent to: https://api-localhost:8081/products
            var responseString = await response.Content.ReadAsStringAsync();

            Assert.AreEqual("{ Shows product data coming from the Api }", responseString);
        }
    }
}

Чтобы выполнить надлежащий тест интеграции для клиентского приложения, я хотел бы сделать вызовы Api из клиентского приложения в Api.

Является ли этоМожно создать один метод тестирования, в котором я могу запустить оба тестовых сервера (клиент и Api) и использовать API через мой клиент?

Я могу себе представить, например, чтобы внедрить тестовый сервер Apiв клиентский тестовый сервер, чтобы я мог использовать API через мое клиентское приложение.

Существует ли что-то подобное следующему?

// Integration test for the client that relies on the Api

[TestFixture]
class IntegrationTestShould
{
    public TestServer GetApiTestServerInstance()
    {
        return new TestServer(new WebHostBuilder()
            .UseStartup<ApiTestServerStartup>()
            .UseEnvironment("TestInMemoryDb"));
    }

    public TestServer GetClientTestServerInstance()
    {
        return new TestServer(new WebHostBuilder()
            .UseStartup<ClientTestServerStartup>()
            .UseEnvironment("Development"));
    }

    [Test]
    public async Task ShowProductsFromApiAtClientLevel()
    {
        using (var apiServer = GetApiTestServerInstance())
        using (var clientServer = GetClientTestServerInstance())
        {
            var client = clientServer.CreateClient(apiServer);
            var response = await client.GetAsync("/products"); // equivalent to: https://client-localhost:8080/products which relies on https://api-localhost:8081/products
            var responseString = await response.Content.ReadAsStringAsync();

            Assert.AreEqual("{ Shows product data coming from the api at client level }",
                 responseString);
        }
    }
}

1 Ответ

0 голосов
/ 05 июня 2018

Благодаря простому, но мощному вопросу mjwills я просто протестировал код таким, какой он был, и были ошибки компиляции.Но это заставило меня вздрогнуть, и я попытался и потерпел неудачу, пока не понял этого.

Что я в основном сделал, так это внедрил экземплярный HttpClient из ApiServer в серверную часть моего клиентского приложения, где HttpRequest был сделан для ApiServer.Поэтому всякий раз, когда клиентское приложение хочет выполнить вызов API к серверу API, оно делает это, используя встроенный HttpClient из ApiServer.

Вот снимок моего интеграционного теста и немного моего клиентского приложениякод, который любой должен направить в правильном направлении:

// My abbreviated and redacted integration test using NUnit
[TestFixture]
public class IntegrationTestShould
{
    public TestServer GetApiTestServerInstance()
    {
        return new TestServer(new WebHostBuilder()
            .UseStartup<ApiTestServerStartup>()
            .UseEnvironment("TestInMemoryDb"));
    }

    public TestServer GetClientTestServerInstance(TestServer apiTestServer)
    {
        // In order to get views rendered:
        // 1. ContentRoot folder must be set when TestServer is built (or views are not found)
        // 2. .csproj file of test project must be adjusted, see http://www.dotnetcurry.com/aspnet-core/1420/integration-testing-aspnet-core (or references for view rendering are missing)

        var apiHttpClient = apiTestServer.CreateClient();
        apiHttpClient.BaseAddress = new Uri(@"https://api-localhost:8081");
        var currentDirectory =
            Path.GetDirectoryName(Path.GetDirectoryName(TestContext.CurrentContext.TestDirectory));
        var contentRoot = Path.GetFullPath(Path.Combine(currentDirectory, @"..\..\ProjectThatContainsViews"));
        return new TestServer(new WebHostBuilder()
            .UseStartup<ClientTestServerStartup>()
            .UseContentRoot(contentRoot)
            // register instantiated apiHttpClient in client app
            .ConfigureServices(collection => collection.AddSingleton(apiHttpClient))
            .UseEnvironment("ClientTestServer"));
    }

    [Test]
    public async Task CorrectlyReturnProductsViewResult()
    {
        using (var apiServer = GetApiTestServerInstance())
        using (var clientServer = GetClientTestServerInstance(apiServer))
        {
            var clientHttpClient = clientServer.CreateClient();
            var response = await clientHttpClient.GetAsync("/products");
            var responseString = await response.Content.ReadAsStringAsync();
            response.EnsureSuccessStatusCode();

            Assert.AreEqual("text/html; charset=utf-8",
                response.Content.Headers.ContentType.ToString());
        }
    }
}

// My heavily abbreviated and redacted client app backend
public class HttpRequestBuilder
{
    private readonly HttpClient _httpClient;
    public HttpRequestBuilder(IServiceProvider serviceProvider)
    {
        // get instantiated apiHttpClient from client app dependency container (when running in test environment)
        // or create new one (the case when running in environment other than test)
        _httpClient = serviceProvider.GetService(typeof(HttpClient)) as HttpClient ?? new HttpClient();
    }

    public async Task<HttpResponseMessage> SendAsync()
    {
        // Setup request
        var request = new HttpRequestMessage
        {
            Method = HttpMethod.Get,
            RequestUri = new Uri(@"https://api-localhost:8081/products")
        };

        // Send request
        var result = await _httpClient.SendAsync(request);

        // should have returned product data from api
        var content = await result.Content.ReadAsStringAsync(); 

        return result; // api product data processed further at client app level
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...