Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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!)

like image 761
Pure.Krome Avatar asked Mar 06 '14 11:03

Pure.Krome


People also ask

How to mock HttpClient in unit tests?

Mocking HttpClient is possible although an arduous task. Luckily there is still a great way to unit test the code. The solution is to mock HttpMessageHandler and pass this object to the HttpClient constructor. When we use the message handler to make HTTP requests, we achieve our unit testing goals.

Can you mock HttpClient?

HttpClient's extensibility lies in the HttpMessageHandler passed to the constructor. Its intent is to allow platform specific implementations, but you can also mock it. There's no need to create a decorator wrapper for HttpClient.

How do you mock HttpRequestMessage?

Returns("my_ticket"); Mock<HttpRequestMessage> req = new Mock<HttpRequestMessage>(); req. Setup(m => m. CreateResponse( HttpStatusCode. OK, "value")) .

What can be mocked with Moq?

Unit testing is a powerful way to ensure that your code works as intended. It's a great way to combat the common “works on my machine” problem. Using Moq, you can mock out dependencies and make sure that you are testing the code in isolation. Moq is a mock object framework for .


2 Answers

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); 
like image 180
Darrel Miller Avatar answered Sep 17 '22 21:09

Darrel Miller


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.

like image 37
Fedaykin Avatar answered Sep 16 '22 21:09

Fedaykin