Модульное тестирование HTTP-клиента - PullRequest
0 голосов
/ 31 января 2020

У меня есть следующий код с использованием HttpClient. Я новичок в C# и хотел бы узнать, как выполнить модульное тестирование моего HttpClient, но не уверен, с чего начать. Вот мой код:

 protected override async Task PopulateData()
        {
            using (var client = new HttpClient())
            {
                var token = "private token";
                var requestUrl = api_url_here;
                var authenticatedRequestUrl = requestUrl + $"{token}";
                var response = await client.GetAsync(authenticatedRequestUrl);
                var stringResult = await response.Content.ReadAsStringAsync();

                // do something
            }
        }

Я видел много разных статей, предлагающих разные способы модульного тестирования, но я не уверен, как их правильно использовать. Например, я видел этот шаблон модульного тестирования на многих веб-сайтах:

  [Test]
        public async Task MockingHTTP()
        {
            var requestUri = new Uri("");
            var expectedResponse = "Response";
            var mockHandler = new Mock<HttpMessageHandler>();

            mockHandler.Protected()
                .Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(),
                ItExpr.IsAny<CancellationToken>())
                .ReturnsAsync(new HttpResponseMessage(Net.HttpStatusCode.OK));

            var httpClient = new HttpClient(mockHandler.Object);
            var result = await httpClient.GetStringAsync(requestUri).ConfigureAwait(false);
            Assert.AreEqual(expectedResponse, result);

            }
        }

Однако я не знаю, как применить этот подход к моему коду. Кто-нибудь может указать мне правильное направление для успешного модульного тестирования HttpClient?

1 Ответ

2 голосов
/ 31 января 2020

Первое, что нужно сделать при модульном тестировании, - это идентифицировать вашу «тестируемую систему» ​​или SUT. Это то, что вам нужно проверить поведение. Любые зависимости вашего SUT должны быть смоделированы, вы не должны использовать реальную версию.

В этом случае вы используете HttpClient, но у вас нет способа использовать другой обработчик в вашем методе. Использование другого обработчика - это самый простой способ подделать ответы для HttpClient. HttpClient принимает другой обработчик через конструктор. Таким образом, вам нужно изменить ваш код следующим образом:

public class YourClassName
{
    private readonly HttpMessageHandler _httpMessageHandler;

    public YourClassName(HttpMessageHandler httpMessageHandler)
    {
        _httpMessageHandler = httpMessageHandler;
    }

    protected override async Task PopulateData()
    {
        using (var client = new HttpClient(_httpMessageHandler))
        {
            var token = "private token";
            var requestUrl = api_url_here;
            var authenticatedRequestUrl = requestUrl + $"{token}";
            var response = await client.GetAsync(authenticatedRequestUrl);
            var stringResult = await response.Content.ReadAsStringAsync();

            // do something
        }
    }
}

Теперь это тестируемый модуль, потому что вы можете издеваться над HttpMessageHandler. Но код для этого громоздкий . А учитывая другие fl aws, которые вы использовали при использовании HttpClient, вероятно, лучше вообще не использовать HttpClient. См .:

Моя команда использует вместо этого Flurl . У него более приятный синтаксис, нет странного выигрыша с IDisposable, который есть у HttpClient, и его легко выполнить модульное тестирование.

protected override async Task PopulateData()
{
    var token = "private token";
    var requestUrl = api_url_here;
    var authenticatedRequestUrl = requestUrl + $"{token}";
    var stringResult = authenticatedRequestUrl.
    var response = await authenticatedRequestUrl.GetAsync();
    var stringResult = await response.Content.ReadAsStringAsync();

    // do something
}

Тогда ваш модульный тест станет намного проще:

[Test]
public async Task PopulateDataTest()
{
    var requestUri = new Uri("SomeUriWithAToken");
    var expectedResponse = "some response body";
    var systemUnderTest = new YourClassName();

    using (var httpTest = new HttpTest())
    {
        httpTest.RespondWith(expectedResponse);
        var result = await systemUnderTest.PopulateData();
        Assert.AreEqual(expectedResponse, result);
        httpTest.ShouldHaveCalled(requestUri);
    }
}

У Flurl отличная документация. Вы можете сделать так, чтобы он возвращал все виды ответов, или даже автоматически десериализовать ответ на класс C#.

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