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

后端 未结 4 1772
不思量自难忘°
不思量自难忘° 2020-12-07 17:48

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

相关标签:
4条回答
  • 2020-12-07 17:57

    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 async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
            {
                if (_FakeResponses.ContainsKey(request.RequestUri))
                {
                    return _FakeResponses[request.RequestUri];
                }
                else
                {
                    return 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);
    
    0 讨论(0)
  • 2020-12-07 18:08

    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.

    0 讨论(0)
  • 2020-12-07 18:16

    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.

    0 讨论(0)
  • 2020-12-07 18:17

    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 });
            }
        }
    }
    
    0 讨论(0)
提交回复
热议问题