Mocking HttpClient GetAsync с использованием библиотеки Moq в тесте Xunit - PullRequest
1 голос
/ 09 мая 2019

Я пишу простой модульный тест для этого небольшого сервиса, который просто вызывает внешние API:

public class ApiCaller : IApiCaller
{
    private readonly IHttpClientFactory _httpFactory;

    public ApiCaller(IHttpClientFactory httpFactory)
    {
        _httpFactory = httpFactory;
    }

    public async Task<T> GetResponseAsync<T>(Uri url)
    {
        using (HttpClient client = _httpFactory.CreateClient())
        {
            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
            client.Timeout = TimeSpan.FromSeconds(20);
            using (HttpResponseMessage response = await client.GetAsync(url))
            {
                response.EnsureSuccessStatusCode();
                string responseBody = await response.Content.ReadAsStringAsync();

                return JsonConvert.DeserializeObject<T>(responseBody);
            }

        }
    }
}

Мой первый вопрос: кажется, что это не очень распространенная практика насмешек и, следовательно, тестирования таких сервисов, и мне интересно, есть ли какое-то конкретное объяснение.

Во-вторых, я попытался написать простой модульный тест, но не могу смоделировать вызов GetAsync , поскольку HttpClient не реализует никакого интерфейса.

public class ApiCallerTest
{
    private readonly ApiCaller _target;
    private readonly Mock<IHttpClientFactory> _httpClientFactory;


    public ApiCallerTest()
    {
        _httpClientFactory = new Mock<IHttpClientFactory>();
        _target = new ApiCaller(_httpClientFactory.Object);
    }

    [Fact]
    public void WhenACorrectUrlIsProvided_ServiceShouldReturn()
    {


        var client = new HttpClient();
        _httpClientFactory.Setup(x => x.CreateClient(It.IsAny<string>())).Returns(client);

        var httpMessageHandler = new Mock<HttpMessageHandler>();

    }

}

1 Ответ

1 голос
/ 09 мая 2019

Сначала настройте свой макет HttpMessageHandler и передайте его конструктору HttpClient. Затем вы можете настроить Mock для метода GetAsync в обработчике следующим образом:

        var httpMessageHandler = new Mock<HttpMessageHandler>();

        // Setup Protected method on HttpMessageHandler mock.
        httpMessageHandler.Protected()
            .Setup<Task<HttpResponseMessage>>(
                "GetAsync",
                ItExpr.IsAny<string>(),
                ItExpr.IsAny<CancellationToken>()
            )
            .ReturnsAsync((HttpRequestMessage request, CancellationToken token) =>
            {
                HttpResponseMessage response = new HttpResponseMessage();

                // Setup your response for testing here.

                return response;
            });

        var client = new HttpClient(httpMessageHandler.Object);

Это изменение от модульного теста, который я использую для макета SendAsync, но он должен быть очень похожим.

...