Как смоделировать IHttpClientFactory с помощью типизированных клиентов - PullRequest
0 голосов
/ 17 июня 2019

Я пытаюсь правильно добавить HttpClient в свое приложение, одновременно позволяя смоделировать фабрику клиентов для модульного тестирования. Я использую этот в качестве ресурса.

В моем Startup.cs

services.AddHttpClient<IUploader, Uploader>()
    .ConfigurePrimaryHttpMessageHandler(() =>
    {
        if (somecheckismet)
            return new HttpClientHandler() { ServerCertificateCustomValidationCallback = delegate { return true; } };
        return new HttpClientHandler();
    });

И мой Uploader.cs

public class Uploader : IUploader
{
    private readonly HttpClient m_httpClient;

    public Uploader(HttpClient client)
    {
        m_httpClient = client;
    }

    public async Task<string> UploadData(string url, Dictionary<string, string> data)
    {
        HttpResponseMessage result;
        try
        {
            result = await m_httpClient.PostAsync(url, new FormUrlEncodedContent(data));
            if (result.StatusCode != HttpStatusCode.OK)
            {
                return "Some error message;
            }
            else
            {
                return null; // Success!
            }
        }
        catch (Exception ex)
        {
            return "Uh-oh!";
        }
    }
}

Как видите, я пытаюсь ввести зависимость HttpClient в Uploader. Однако, теперь, когда я это сделал, как мне приступить к модульному тестированию Uploader? Раньше это работало бы для внедрения зависимостей HttpClientHandler, которые можно было бы удалить. Тем не менее, теперь, так как я пытаюсь использовать IHttpClientFactory, похоже, мне нужно ввести HttpClient.

Любая помощь будет принята с благодарностью.

Ответы [ 2 ]

0 голосов
/ 17 июня 2019

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

Ваш класс Uploader уже настроен для модульного тестирования, так как вы передаете свой экземпляр HttpClient.Для модульного тестирования около HttpClient вы не извлекаете экземпляр HttpClient, а заменяете HttpMessageHandler, который использует HttpClient.Вот ссылка на отличный пост со всеми подробностями

Код взят из статьи

// ARRANGE
var handlerMock = new Mock<HttpMessageHandler>(MockBehavior.Strict);
handlerMock
   .Protected()
   // Setup the PROTECTED method to mock
   .Setup<Task<HttpResponseMessage>>(
      "SendAsync",
      ItExpr.IsAny<HttpRequestMessage>(),
      ItExpr.IsAny<CancellationToken>()
   )
   // prepare the expected response of the mocked http call
   .ReturnsAsync(new HttpResponseMessage()
   {
      StatusCode = HttpStatusCode.OK,
      Content = new StringContent("[{'id':1,'value':'1'}]"),
   })
   .Verifiable();

// use real http client with mocked handler here
var httpClient = new HttpClient(handlerMock.Object)
{
   BaseAddress = new Uri("http://test.com/"),
};

var subjectUnderTest = new MyTestClass(httpClient);

// ACT
var result = await subjectUnderTest
   .GetSomethingRemoteAsync('api/test/whatever');

// ASSERT
result.Should().NotBeNull(); // this is fluent assertions here...
result.Id.Should().Be(1);

// also check the 'http' call was like we expected it
var expectedUri = new Uri("http://test.com/api/test/whatever");

handlerMock.Protected().Verify(
   "SendAsync",
   Times.Exactly(1), // we expected a single external request
   ItExpr.Is<HttpRequestMessage>(req =>
      req.Method == HttpMethod.Get  // we expected a GET request
      && req.RequestUri == expectedUri // to this uri
   ),
   ItExpr.IsAny<CancellationToken>()
);
0 голосов
/ 17 июня 2019

Похоже, вы могли бы просто продолжать насмехаться над HttpClientHandler и использовать его для создания HttpClient

public void TestMethod() 
{
    var handler = // Mock the HttpClientHandler;
    var client = new HttpClient(handler);
    var uploader = new Uploader(client);

    // Draw the rest of the owl
}
...