8

I run my tests inside nUnit and normally I can mock out dependencies and have then Return certain values or throw errors.

I have a class that as an internal HttpClient and I would like to test the class, what are my options.

here is my code, its not complete so as not to flood the message. As you can see I am using the HttpClient internally and not injected as a dependency. The class throws a number of custom exceptions, I would like to Moq these otherwise I need to pass REAL username and passwords that would give me the status codes i required to throw the exceptions.

Anyone have an ideas? If I can't mock the httpclient then i can never test my class that it raises exceptions.

Do I really have to change HttpClient to a dependency on the constructor ?

public bool ItemsExist(string itemValue)
{

    var relativeUri = string.Format(UrlFormatString, itemValue.ToUpper());

    var uri = new Uri(new Uri(this.baseUrl), relativeUri);

    using (var client = new HttpClient())
    {
        client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", this.encodedCredentials);
        client.DefaultRequestHeaders.Accept.Add(
            new MediaTypeWithQualityHeaderValue("application/json"));

        var response = client.GetAsync(uri).Result;

        switch (response.StatusCode)
        {
            case HttpStatusCode.Unauthorized:
                // DO something here
                throw new CustomAuthorizationException();

            case HttpStatusCode.Forbidden:
                throw new CustomAuthenticationException();

        }

        return true;
Martin
  • 23,844
  • 55
  • 201
  • 327

3 Answers3

23

Let me suggest a bit easier solution, without a need to abstract/wrap httpclient, that i believe works perfectly with mocking frameworks.

You need to create a class for fake HttpMessageHandler, like here:

public class FakeHttpMessageHandler : HttpMessageHandler
{
    public virtual HttpResponseMessage Send(HttpRequestMessage request)
    {
        throw new NotImplementedException("Rember to setup this method with your mocking framework");
    }

    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
    {
        return Task.FromResult(Send(request));
    }
}

Such created HttpMessageHandler can be used when instantiating HttpClient:

var msgHandler = new Mock<FakeHttpMessageHandler>() { CallBase = true };
var fakeclient = new HttpClient(msgHandler.Object);

And you can setup methods (here using Moq):

msgHandler.Setup(t => t.Send(It.Is<HttpRequestMessage>(
            msg =>
                    msg.Method == HttpMethod.Post &&
                    msg.RequestUri.ToString() == "http://test.te/item/123")))
                    .Returns(new HttpResponseMessage(System.Net.HttpStatusCode.NotFound));

You can now user fakeclient instead when necessary.

ITmeze
  • 1,902
  • 2
  • 21
  • 32
11

You can't unit test it like that. It's like you mentioned: HttpClient is a dependency, and as such, it should be injected.

Personally, I would create my own IHttpClient interface, implemented by HttpClientWrapper, which wraps around the System.Net.HttpClient. IHttpClient would then be passed as a dependency to your object's contructor.

As follows, HttpClientWrapper can't be unit tested. I would, however, write a couple of integration tests to make sure the wrapper is well written.

Edit:

IHttpClient doesn't have to be a "valid" interface for HttpClient. It only has to be an interface that suits your needs. It can have as many or as few methods as you want.

Picture this: HttpClient allows you to do many things. But in your project, you're only calling the GetAsync(uri).Result method, nothing else.

Given this scenario, you would write the following interface and implementation:

interface IHttpClient
{
    HttpResponseMessage Get(string uri);
}

class HttpClientWrapper : IHttpClient
{
    private readonly HttpClient _client;

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


    public HttpResponseMessage Get(string uri)
    {
        return _client.GetAsync(new Uri(uri)).Result;
    }
}

So, as I stated previously, the interface only has to suit your needs. You don't have to wrap around the WHOLE HttpClient class.

Obviously, you would then moq your object like this:

var clientMock = new Mock<IHttpClient>();
//setup mock
var myobj = new MyClass(clientMock.object);

And to create an actual object:

var client = new HttpClientWrapper(new HttpClient());
var myobj = new MyClass(client );

Edit2

OH! And don't forget that IHttpClient should also extend the IDisposable interface, very important!

dcastro
  • 66,540
  • 21
  • 145
  • 155
  • Sounds good, but IHttpClient, How would I ensure I create a valid Interface for HttpClient... an Interface can't inherit from a HttpClient... Do I need to create Interface manually ? – Martin Sep 10 '13 at 16:11
  • Do you have an example ? – Martin Sep 10 '13 at 16:12
  • 1
    I've added an example. – dcastro Sep 10 '13 at 16:27
  • That is great, I ended up implementing all members in the wrapper. Thanks for the info. – Martin Sep 11 '13 at 10:16
  • 1
    This seems like an incomplete solution to me. The problem is that in the question the HttpClient gets new-ed up inside a method, which means a new one is needed every time. Therefore, injecting a wrapper which provides a single HttpClient also inside it's constructor is treating the HttpClient as a singleton, which is incorrect. In order to provide a per-instance HttpClient I think we need to inject something like a factory which creates HttpClients (or IHttpClient) on request. – Robert Noack Nov 25 '14 at 16:36
  • @RobertNoack Correct, my solution is slightly different than the original code, but it does illustrate my point. You should inject an `IHttpFactory` which returns instances of `IHttpClient`. Moreover, if using DI containers such as Castle Windsor, you usually get these factories for free - you just write the factory's interface, and Castle will generate a type that implements that interface at runtime. – dcastro Nov 25 '14 at 16:54
  • 1
    HttpClient does not need to be disposed according to its developers even though it implements the IDisposable interface. So you don't need the IDisposable. – Muhammad Rehan Saeed Jul 27 '15 at 09:34
  • @MuhammadRehanSaeed "according to its developers" - can you please post your source? – dcastro Jul 27 '15 at 09:37
  • http://stackoverflow.com/questions/15705092/do-httpclient-and-httpclienthandler-have-to-be-disposed – Muhammad Rehan Saeed Jul 27 '15 at 10:12
3

Another option is to use Flurl [disclosure: I'm the author], a library for building and calling URLs. It includes testing helpers that make faking all HTTP incredibly easy. No need for wrapper interfaces.

For starters, your HTTP code itself would look something like this:

using Flurl;
using Flurl.Http;

...

try {
    var response = this.baseUrl
        .AppendPathSegment(relativeUri)
        .WithBasicAuth(username, password)
        .WithHeader("Accept", "application/json")
        .GetAsync().Result;

    return true;
}
catch (FlurlHttpException ex) {
    // Flurl throws on unsuccessful responses. Null-check ex.Response,
    // then do your switch on ex.Response.StatusCode.
}

Now for the testing fun:

using Flurl.Http.Testing;

...

[Test]
public void ItemsExists_SuccessResponse() {
    // kick Flurl into test mode - all HTTP calls will be faked and recorded
    using (var httpTest = new HttpTest()) {
        // arrange
        test.RespondWith(200, "{status:'ok'}");
        // act
        sut.ItemExists("blah");
        // assert
        test.ShouldHaveCalled("http://your-url/*");
    }
}

Get it on NuGet:

PM> Install-Package Flurl.Http
Todd Menier
  • 37,557
  • 17
  • 150
  • 173