How to pass in a mocked HttpClient in a .NET test?

C#.NetMockingDotnet HttpclientMicrosoft Fakes

C# Problem Overview


I have a service which uses Microsoft.Net.Http to retrieve some Json data. Great!

Of course, I don't want my unit test hitting the actual server (otherwise, that's an integration test).

Here's my service ctor (which uses dependency injection...)

public Foo(string name, HttpClient httpClient = null)
{
...
}

I'm not sure how I can mock this with ... say .. Moq or FakeItEasy.

I want to make sure that when my service calls GetAsync or PostAsync .. then i can fake those calls.

Any suggestions how I can do that?

I'm -hoping- i don't need to make my own Wrapper .. cause that's crap :( Microsoft can't have made an oversight with this, right?

(yes, it's easy to make wrappers .. i've done them before ... but it's the point!)

C# Solutions


Solution 1 - C#

You can replace the core HttpMessageHandler with a fake one. Something that looks like this...

public class FakeResponseHandler : DelegatingHandler
{
    private readonly Dictionary<Uri, HttpResponseMessage> _FakeResponses = new Dictionary<Uri, HttpResponseMessage>();

    public void AddFakeResponse(Uri uri, HttpResponseMessage responseMessage)
    {
        _FakeResponses.Add(uri, responseMessage);
    }

    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
    {
        if (_FakeResponses.ContainsKey(request.RequestUri))
        {
            return Task.FromResult(_FakeResponses[request.RequestUri]);
        }
        else
        {
            return Task.FromResult(new HttpResponseMessage(HttpStatusCode.NotFound) { RequestMessage = request });
        }
    }
}

and then you can create a client that will use the fake handler.

var fakeResponseHandler = new FakeResponseHandler();
fakeResponseHandler.AddFakeResponse(new Uri("http://example.org/test"), new HttpResponseMessage(HttpStatusCode.OK));

var httpClient = new HttpClient(fakeResponseHandler);

var response1 = await httpClient.GetAsync("http://example.org/notthere");
var response2 = await httpClient.GetAsync("http://example.org/test");

Assert.Equal(response1.StatusCode,HttpStatusCode.NotFound);
Assert.Equal(response2.StatusCode, HttpStatusCode.OK);

Solution 2 - C#

I know that this is an old question but I stumbled with it during a search on this topic and found a very nice solution to make testing HttpClient easier.

It is available via nuget:

https://github.com/richardszalay/mockhttp

PM> Install-Package RichardSzalay.MockHttp

Here is a quick look on the usage:

var mockHttp = new MockHttpMessageHandler();

// Setup a respond for the user api (including a wildcard in the URL)
mockHttp.When("http://localost/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 = await client.GetAsync("http://localost/api/user/1234");
// or without await: var response = client.GetAsync("http://localost/api/user/1234").Result;

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

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

More info on the github project page. Hope this can be useful.

Solution 3 - C#

I would just make a small change to @Darrel Miller's answer, which is using Task.FromResult to avoid the warning about an async method expecting an await operator.

public class FakeResponseHandler : DelegatingHandler
{
    private readonly Dictionary<Uri, HttpResponseMessage> _FakeResponses = new Dictionary<Uri, HttpResponseMessage>();

    public void AddFakeResponse(Uri uri, HttpResponseMessage responseMessage)
    {
        _FakeResponses.Add(uri, responseMessage);
    }

    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
    {
        if (_FakeResponses.ContainsKey(request.RequestUri))
        {
            return Task.FromResult(_FakeResponses[request.RequestUri]);
        }
        else
        {
            return Task.FromResult(new HttpResponseMessage(HttpStatusCode.NotFound) { RequestMessage = request });
        }
    }
}

Solution 4 - C#

You might take a look at Microsoft Fakes, especially at the Shims-section. With them, you're able to modify the behaviours of your HttpClient itself. Prerequisite is, that you're using VS Premium or Ultimate.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPure.KromeView Question on Stackoverflow
Solution 1 - C#Darrel MillerView Answer on Stackoverflow
Solution 2 - C#FedaykinView Answer on Stackoverflow
Solution 3 - C#Rui TabordaView Answer on Stackoverflow
Solution 4 - C#ElGauchoooView Answer on Stackoverflow