Подтвердить что ты не робот

Stubbing или Mocking ASP.NET Web API HttpClient

Я использую новые биты веб-API в проекте, и я обнаружил, что я не могу использовать обычный HttpMessageRequest, так как мне нужно добавить клиентские сертификаты в запрос. В результате я использую HttpClient (поэтому я могу использовать WebRequestHandler). Все это хорошо работает, за исключением того, что он не является незаменимым, хотя бы для Rhino Mocks.

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

4b9b3361

Ответ 1

Я использую Moq, и я могу заглушить HttpClient. Я думаю, что это то же самое для Rhino Mock (я не пытался сам). Если вы просто хотите заглушить HttpClient, код ниже должен работать:

var stubHttpClient = new Mock<HttpClient>();
ValuesController controller = new ValuesController(stubHttpClient.Object);

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

Самые популярные схемы изоляции/mock-объектов не позволят вам заглушить/настроить на не виртуальных элементах Например, приведенный ниже код генерирует исключение

stubHttpClient.Setup(x => x.BaseAddress).Returns(new Uri("some_uri");

Вы также упомянули, что хотите избежать создания обертки, потому что вы будете обматывать множество членов HttpClient. Непонятно, почему вам нужно обернуть множество методов, но вы можете легко обернуть только те методы, которые вам нужны.

Например:

public interface IHttpClientWrapper  {   Uri BaseAddress { get;  }     }

public class HttpClientWrapper : IHttpClientWrapper
{
   readonly HttpClient client;

   public HttpClientWrapper()   {
       client = new HttpClient();
   }

   public Uri BaseAddress   {
       get
       {
           return client.BaseAddress;
       }
   }
}

Другие варианты, которые, как я думаю, могут принести вам пользу (много примеров, поэтому я не буду писать код) Microsoft Moles Framework http://research.microsoft.com/en-us/projects/moles/ Microsoft Fakes: (если вы используете VS2012 Ultimate) http://msdn.microsoft.com/en-us/library/hh549175.aspx

Ответ 2

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

Если вы создаете какой-либо класс, которому требуется HttpClient принять его как параметр впрыскивания зависимостей в конструкторе, тогда при модульном тестировании вы можете передать HttpClient, который был введен с вашим собственным HttpMessageHandler. Этот простой класс имеет только один абстрактный метод, который вам нужно реализовать следующим образом:

public class FakeHttpMessageHandler : HttpMessageHandler
    {
    public HttpRequestMessage RequestMessage { get; private set; }

    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
        RequestMessage = request;
        return Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK));
        }
    }

Мой тривиальный пример просто сохраняет HttpRequestMessage в публичном свойстве для последующего контроля и возвращает HTTP 200 (OK), но вы можете увеличить его, добавив конструктор, который устанавливает возвращаемый результат.

Вы бы использовали этот класс следующим образом:

public void foo()
    {
    //Arrange
    var fakeHandler = new FakeHttpMessageHandler();
    var client = new HttpClient(fakeHandler);
    var SUT = new ClassUnderTest(client);

    //Act
    SUT.DomSomething();

    //Assert
    fakeHandler.RequestMessage.Method.ShouldEqual(HttpMethod.Get); // etc...
    }

Существуют ограничения для этого подхода, например, в методе, который делает несколько запросов или потребностей для создания нескольких HttpClient s, тогда поддельный обработчик может начать становиться слишком сложным. Однако это может быть полезно для простых случаев.

Ответ 3

Я выпустил библиотеку несколько месяцев назад под названием MockHttp, которая может быть полезна. Он использует пользовательский HttpMessageHandler с плавным (и расширяемым) API. Вы можете ввести обработанного обработчика (или HttpClient) в свой класс обслуживания и он будет отвечать, как он был настроен.

Ниже показано основное использование. Методы When и Respond имеют множество перегрузок, включая выполнение пользовательской логики. Документация на странице GitHub представлена ​​более подробно.

var mockHttp = new MockHttpMessageHandler();

// Setup a respond for the user api (including a wildcard in the URL)
mockHttp.When("http://localhost/api/user/*")
        .Respond("application/json", "{'name' : 'Test McGee'}"); // Respond with JSON

// Inject the handler or client into your application code
var client = new HttpClient(mockHttp);

var response = async client.GetAsync("http://localhost/api/user/1234");
// or without async: var response = client.GetAsync(...).Result;

var json = await response.Content.ReadAsStringAsync();

// No network connection required
Console.Write(json); // {'name' : 'Test McGee'}