How to pass in a mocked HttpClient in a .NET test?
C#.NetMockingDotnet HttpclientMicrosoft FakesC# 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.