Mocking HttpClient GetAsync by using Moq library in Xunit test - c#

I am writing a simple unit test for this small service that simply calls external APIs:
public class ApiCaller : IApiCaller
{
private readonly IHttpClientFactory _httpFactory;
public ApiCaller(IHttpClientFactory httpFactory)
{
_httpFactory = httpFactory;
}
public async Task<T> GetResponseAsync<T>(Uri url)
{
using (HttpClient client = _httpFactory.CreateClient())
{
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
client.Timeout = TimeSpan.FromSeconds(20);
using (HttpResponseMessage response = await client.GetAsync(url))
{
response.EnsureSuccessStatusCode();
string responseBody = await response.Content.ReadAsStringAsync();
return JsonConvert.DeserializeObject<T>(responseBody);
}
}
}
}
My first question is: it doesn't seem to be very common practice mocking and therefore testing such services and I am wondering if there is some specific explanation.
Second, I tried to write a simple unit test but I cannot Mock the GetAsync call since HttpClient doesn't implement any interface.
public class ApiCallerTest
{
private readonly ApiCaller _target;
private readonly Mock<IHttpClientFactory> _httpClientFactory;
public ApiCallerTest()
{
_httpClientFactory = new Mock<IHttpClientFactory>();
_target = new ApiCaller(_httpClientFactory.Object);
}
[Fact]
public void WhenACorrectUrlIsProvided_ServiceShouldReturn()
{
var client = new HttpClient();
_httpClientFactory.Setup(x => x.CreateClient(It.IsAny<string>())).Returns(client);
var httpMessageHandler = new Mock<HttpMessageHandler>();
}
}

The code below is what you should use regardless of the method in the HttpClient class you use (GetAsync, PostAsync, etc.). All these methods are created for the convenience of the programmer. What they do is use the SendAsync method of the HttpMessageHandler class.
var mockHttpMessageHandler = new Mock<HttpMessageHandler>();
// Setup Protected method on HttpMessageHandler mock.
mockHttpMessageHandler.Protected()
.Setup<Task<HttpResponseMessage>>(
"SendAsync",
ItExpr.IsAny<HttpRequestMessage>(),
ItExpr.IsAny<CancellationToken>()
)
.ReturnsAsync((HttpRequestMessage request, CancellationToken token) =>
{
HttpResponseMessage response = new HttpResponseMessage();
// configure your response here
return response;
});
And then you use it this way:
var httpClient = new HttpClient(mockHttpMessageHandler.Object);
var result = await httpClient.GetAsync(url, cancellationToken);
You can also take a look here How to create mock for httpclient getasync method?

Setup your Mock HttpMessageHandler first and pass it to the constructor of your HttpClient. Then you can setup a Mock for the GetAsync method on the handler like this:
var httpMessageHandler = new Mock<HttpMessageHandler>();
// Setup Protected method on HttpMessageHandler mock.
httpMessageHandler.Protected()
.Setup<Task<HttpResponseMessage>>(
"GetAsync",
ItExpr.IsAny<string>(),
ItExpr.IsAny<CancellationToken>()
)
.ReturnsAsync((HttpRequestMessage request, CancellationToken token) =>
{
HttpResponseMessage response = new HttpResponseMessage();
// Setup your response for testing here.
return response;
});
var client = new HttpClient(httpMessageHandler.Object);
This is modified from a unit test I use to mockSendAsync, but it should be very similar.

Related

How to inject mocked httpservice to asp.net core controller [duplicate]

.NET Core 2.1 comes with this new factory called HttpClientFactory, but I can't figure out how to mock it to unit test some methods that include REST service calls.
The factory is being injected using .NET Core IoC container, and what the method does is create a new client from the factory:
var client = _httpClientFactory.CreateClient();
And then using the client to get data from a REST service:
var result = await client.GetStringAsync(url);
The HttpClientFactory is derived from IHttpClientFactory Interface So it is just a matter of creating a mock of the interface
var mockFactory = new Mock<IHttpClientFactory>();
Depending on what you need the client for, you would then need to setup the mock to return a HttpClient for the test.
This however requires an actual HttpClient.
var clientHandlerStub = new DelegatingHandlerStub();
var client = new HttpClient(clientHandlerStub);
mockFactory.Setup(_ => _.CreateClient(It.IsAny<string>())).Returns(client);
IHttpClientFactory factory = mockFactory.Object;
The factory can then be injected into the dependent system under test when exercising the test.
If you do not want the client calling actual endpoints then you will need to create a fake delegate handler to intercept the requests.
Example of the handler stub used to fake the requests
public class DelegatingHandlerStub : DelegatingHandler {
private readonly Func<HttpRequestMessage, CancellationToken, Task<HttpResponseMessage>> _handlerFunc;
public DelegatingHandlerStub() {
_handlerFunc = (request, cancellationToken) => Task.FromResult(request.CreateResponse(HttpStatusCode.OK));
}
public DelegatingHandlerStub(Func<HttpRequestMessage, CancellationToken, Task<HttpResponseMessage>> handlerFunc) {
_handlerFunc = handlerFunc;
}
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) {
return _handlerFunc(request, cancellationToken);
}
}
Taken from an answer I gave here
Reference Mock HttpClient using Moq
Suppose you have a controller
[Route("api/[controller]")]
public class ValuesController : Controller {
private readonly IHttpClientFactory _httpClientFactory;
public ValuesController(IHttpClientFactory httpClientFactory) {
_httpClientFactory = httpClientFactory;
}
[HttpGet]
public async Task<IActionResult> Get() {
var client = _httpClientFactory.CreateClient();
var url = "http://example.com";
var result = await client.GetStringAsync(url);
return Ok(result);
}
}
and wanted to test the Get() action.
public async Task Should_Return_Ok() {
//Arrange
var expected = "Hello World";
var mockFactory = new Mock<IHttpClientFactory>();
var configuration = new HttpConfiguration();
var clientHandlerStub = new DelegatingHandlerStub((request, cancellationToken) => {
request.SetConfiguration(configuration);
var response = request.CreateResponse(HttpStatusCode.OK, expected);
return Task.FromResult(response);
});
var client = new HttpClient(clientHandlerStub);
mockFactory.Setup(_ => _.CreateClient(It.IsAny<string>())).Returns(client);
IHttpClientFactory factory = mockFactory.Object;
var controller = new ValuesController(factory);
//Act
var result = await controller.Get();
//Assert
result.Should().NotBeNull();
var okResult = result as OkObjectResult;
var actual = (string) okResult.Value;
actual.Should().Be(expected);
}
In addition to the previous post that describes how to setup a stub, you can just use Moq to setup the DelegatingHandler:
var clientHandlerMock = new Mock<DelegatingHandler>();
clientHandlerMock.Protected()
.Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>())
.ReturnsAsync(new HttpResponseMessage(HttpStatusCode.OK))
.Verifiable();
clientHandlerMock.As<IDisposable>().Setup(s => s.Dispose());
var httpClient = new HttpClient(clientHandlerMock.Object);
var clientFactoryMock = new Mock<IHttpClientFactory>(MockBehavior.Strict);
clientFactoryMock.Setup(cf => cf.CreateClient()).Returns(httpClient).Verifiable();
clientFactoryMock.Verify(cf => cf.CreateClient());
clientHandlerMock.Protected().Verify("SendAsync", Times.Exactly(1), ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>());
I was using the example from #Nkosi but with .NET 5 I got the following warning with the package Microsoft.AspNet.WebApi.Core needed for HttpConfiguration.
Warning NU1701 Package 'Microsoft.AspNet.WebApi.Core 5.2.7' was
restored using '.NETFramework,Version=v4.6.1,
.NETFramework,Version=v4.6.2, .NETFramework,Version=v4.7,
.NETFramework,Version=v4.7.1, .NETFramework,Version=v4.7.2,
.NETFramework,Version=v4.8' instead of the project target framework
'net5.0'. This package may not be fully compatible with your project.
Complete example without using HttpConfiguration:
private LoginController GetLoginController()
{
var expected = "Hello world";
var mockFactory = new Mock<IHttpClientFactory>();
var mockMessageHandler = new Mock<HttpMessageHandler>();
mockMessageHandler.Protected()
.Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>())
.ReturnsAsync(new HttpResponseMessage
{
StatusCode = HttpStatusCode.OK,
Content = new StringContent(expected)
});
var httpClient = new HttpClient(mockMessageHandler.Object);
mockFactory.Setup(_ => _.CreateClient(It.IsAny<string>())).Returns(httpClient);
var logger = Mock.Of<ILogger<LoginController>>();
var controller = new LoginController(logger, mockFactory.Object);
return controller;
}
Source:
HttpConfiguration from System.Web.Http in .NET 5 project
For those looking to achieve the same result of utilising a mock IHttpClientFactory with the HttpClient delegate to avoid making calls to endpoints during testing and who are using a version of .NET Core higher than 2.2 (where it seems the Microsoft.AspNet.WebApi.Core package containing the HttpRequestMessageExtensions.CreateResponse extension is no longer available without relying upon the package targeting the .NET Core 2.2) then the below adaption of Nkosi's answer above has worked for me in .NET 5.
One can simply use an instance of HttpRequestMessage directly if that is all that is required.
public class HttpHandlerStubDelegate : DelegatingHandler
{
private readonly Func<HttpRequestMessage, CancellationToken, Task<HttpResponseMessage>> _handlerFunc;
public HttpHandlerStubDelegate()
{
_handlerFunc = (request, cancellationToken) => Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK));
}
public HttpHandlerStubDelegate(Func<HttpRequestMessage, CancellationToken, Task<HttpResponseMessage>> handlerFunc)
{
_handlerFunc = handlerFunc;
}
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
return _handlerFunc(request, cancellationToken);
}
}
As for the usage in the test Setup method, similarly, I've used an instance of HttpResponseMessage directly. In my case, the factoryMock is then passed into a custom Adapter which wraps around the HttpClient and is therefore set to use our fake HttpClient.
var expected = #"{ ""foo"": ""bar"" }";
var clientHandlerStub = new HttpHandlerStubDelegate((request, cancellationToken) => {
var response = new HttpResponseMessage() { StatusCode = HttpStatusCode.OK, Content = new StringContent(expected) };
return Task.FromResult(response);
});
var factoryMock = new Mock<IHttpClientFactory>();
factoryMock.Setup(m => m.CreateClient(It.IsAny<string>()))
.Returns(() => new HttpClient(clientHandlerStub));
And finally, an example NUnit test body using this which passes.
[Test]
public async Task Subject_Condition_Expectation()
{
var expected = #"{ ""foo"": ""bar"" }";
var result = await _myHttpClientWrapper.GetAsync("https://www.example.com/api/stuff");
var actual = await result.Content.ReadAsStringAsync();
Assert.AreEqual(expected, actual);
}
This code threw this exception for me,
System.InvalidOperationException: The request does not have an associated configuration object or the provided configuration was null.
So included this in the test method, and it works.
var configuration = new HttpConfiguration();
var request = new HttpRequestMessage();
request.SetConfiguration(configuration);
A different approach may be to create an extra class that will internally call the service. This class can be mocked easily.
It is not a direct answer to the question, but it seems a lot less complex and more testable.

Authentication per request using HttpClientFactory .net Core 2.1

How should I use HttpClientFactory to return an instance of HttpClient whose uri and credentials are determined at the point of the call?
The existing code looks like this:
var httpClientHandler = new HttpClientHandler()
{
Credentials = new NetworkCredential(userName, password),
};
HttpClient client = new HttpClient(httpClientHandler);
client.BaseAddress = new Uri(_appSetting.ServiceURI);
your ConfigureServices method in Start up class
services.AddHttpClient("github", c =>
{
//c.BaseAddress = new Uri("https://api.github.com/");
c.DefaultRequestHeaders.Add("Accept", "application/vnd.github.v3+json");
c.DefaultRequestHeaders.Add("User-Agent", "HttpClientFactory-Sample");
}).ConfigurePrimaryHttpMessageHandler(() =>
{
return new HttpClientHandler()
{
UseDefaultCredentials = true,
Credentials = new NetworkCredential("", ""),
};
});
Your Controller will look like this
private readonly IHttpClientFactory _httpClientFactory;
public DataProController(IHttpClientFactory httpClientFactory)
{
_httpClientFactory = httpClientFactory;
}
[HttpGet]
public async Task<ActionResult> Get()
{
var client = _httpClientFactory.CreateClient("github");
client.BaseAddress = new Uri("https://api.github.com/");
string result = await client.GetStringAsync("/");
return Ok(result);
}
You may not be able to set up Network Credentials at the run time when using httpclientfactory and may need to setup up in the startup class. you can find about this issue here.
https://github.com/aspnet/HttpClientFactory/issues/71
You can create an authentication delegating handler like this:
public class AuthenticationHttpMessageHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request,
CancellationToken cancellationToken)
{
// Get the token or other type of credentials here
// string scheme = ... // E.g. "Bearer", "Basic" etc.
// string credentials = ... // E.g. formatted token, user/password etc.
request.Headers.Authorization =
new AuthenticationHeaderValue(scheme, credentials);
return await base.SendAsync(request, cancellationToken).ConfigureAwait(false);
}
}
then add it to the HttpClient builder and to the DI container:
services
.AddTransient<AuthenticationHttpMessageHandler>()
.AddHttpClient("MyClient")
.AddHttpMessageHandler<AuthenticationHttpMessageHandler>();
then use IHttpClientFactory to create HttpClient instances.
The core advantage of this approach is that you clearly separate concerns. You don't touch the primary handler, you don't manage client creation manually, you utilize the whole power of the factory and its builder extension methods. The authentication handler is naturally injected in the pipeline and adds authorization to each request. This handler can be enhanced further by abstracting away the source of credentials and make the handler depend on some IAuthenticationProvider abstraction, which will require only DI configuration and not touching the HttpClient configuration code.
If you using the .net Dependency Injection you can add the configuration for one class into your setup code:
services
.AddTransient<DataLoader>()
.AddHttpClient<DataLoader>().ConfigurePrimaryHttpMessageHandler(() => new HttpClientHandler()
{
Credentials = new NetworkCredential(LoadUsernameFromConfig(), LoadPasswordFromSecureLocation())
});
Add now the DI will inject a HttpClient that uses this credential into the DataLoader class:
public class DataLoader
{
private readonly HttpClient httpClient;
public DataLoader(HttpClient httpClient)
{
this.httpClient = httpClient;
}
public async Task LoadData(string tableName)
{
var json = await httpClient.GetStringAsync("https://protected.example.com/json");
...
}
}
(I would not be able to come up with this code if I had not the answer from Imran Arshad: Thanks!)

How to mock the new HttpClientFactory in .NET Core 2.1 using Moq

.NET Core 2.1 comes with this new factory called HttpClientFactory, but I can't figure out how to mock it to unit test some methods that include REST service calls.
The factory is being injected using .NET Core IoC container, and what the method does is create a new client from the factory:
var client = _httpClientFactory.CreateClient();
And then using the client to get data from a REST service:
var result = await client.GetStringAsync(url);
The HttpClientFactory is derived from IHttpClientFactory Interface So it is just a matter of creating a mock of the interface
var mockFactory = new Mock<IHttpClientFactory>();
Depending on what you need the client for, you would then need to setup the mock to return a HttpClient for the test.
This however requires an actual HttpClient.
var clientHandlerStub = new DelegatingHandlerStub();
var client = new HttpClient(clientHandlerStub);
mockFactory.Setup(_ => _.CreateClient(It.IsAny<string>())).Returns(client);
IHttpClientFactory factory = mockFactory.Object;
The factory can then be injected into the dependent system under test when exercising the test.
If you do not want the client calling actual endpoints then you will need to create a fake delegate handler to intercept the requests.
Example of the handler stub used to fake the requests
public class DelegatingHandlerStub : DelegatingHandler {
private readonly Func<HttpRequestMessage, CancellationToken, Task<HttpResponseMessage>> _handlerFunc;
public DelegatingHandlerStub() {
_handlerFunc = (request, cancellationToken) => Task.FromResult(request.CreateResponse(HttpStatusCode.OK));
}
public DelegatingHandlerStub(Func<HttpRequestMessage, CancellationToken, Task<HttpResponseMessage>> handlerFunc) {
_handlerFunc = handlerFunc;
}
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) {
return _handlerFunc(request, cancellationToken);
}
}
Taken from an answer I gave here
Reference Mock HttpClient using Moq
Suppose you have a controller
[Route("api/[controller]")]
public class ValuesController : Controller {
private readonly IHttpClientFactory _httpClientFactory;
public ValuesController(IHttpClientFactory httpClientFactory) {
_httpClientFactory = httpClientFactory;
}
[HttpGet]
public async Task<IActionResult> Get() {
var client = _httpClientFactory.CreateClient();
var url = "http://example.com";
var result = await client.GetStringAsync(url);
return Ok(result);
}
}
and wanted to test the Get() action.
public async Task Should_Return_Ok() {
//Arrange
var expected = "Hello World";
var mockFactory = new Mock<IHttpClientFactory>();
var configuration = new HttpConfiguration();
var clientHandlerStub = new DelegatingHandlerStub((request, cancellationToken) => {
request.SetConfiguration(configuration);
var response = request.CreateResponse(HttpStatusCode.OK, expected);
return Task.FromResult(response);
});
var client = new HttpClient(clientHandlerStub);
mockFactory.Setup(_ => _.CreateClient(It.IsAny<string>())).Returns(client);
IHttpClientFactory factory = mockFactory.Object;
var controller = new ValuesController(factory);
//Act
var result = await controller.Get();
//Assert
result.Should().NotBeNull();
var okResult = result as OkObjectResult;
var actual = (string) okResult.Value;
actual.Should().Be(expected);
}
In addition to the previous post that describes how to setup a stub, you can just use Moq to setup the DelegatingHandler:
var clientHandlerMock = new Mock<DelegatingHandler>();
clientHandlerMock.Protected()
.Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>())
.ReturnsAsync(new HttpResponseMessage(HttpStatusCode.OK))
.Verifiable();
clientHandlerMock.As<IDisposable>().Setup(s => s.Dispose());
var httpClient = new HttpClient(clientHandlerMock.Object);
var clientFactoryMock = new Mock<IHttpClientFactory>(MockBehavior.Strict);
clientFactoryMock.Setup(cf => cf.CreateClient()).Returns(httpClient).Verifiable();
clientFactoryMock.Verify(cf => cf.CreateClient());
clientHandlerMock.Protected().Verify("SendAsync", Times.Exactly(1), ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>());
I was using the example from #Nkosi but with .NET 5 I got the following warning with the package Microsoft.AspNet.WebApi.Core needed for HttpConfiguration.
Warning NU1701 Package 'Microsoft.AspNet.WebApi.Core 5.2.7' was
restored using '.NETFramework,Version=v4.6.1,
.NETFramework,Version=v4.6.2, .NETFramework,Version=v4.7,
.NETFramework,Version=v4.7.1, .NETFramework,Version=v4.7.2,
.NETFramework,Version=v4.8' instead of the project target framework
'net5.0'. This package may not be fully compatible with your project.
Complete example without using HttpConfiguration:
private LoginController GetLoginController()
{
var expected = "Hello world";
var mockFactory = new Mock<IHttpClientFactory>();
var mockMessageHandler = new Mock<HttpMessageHandler>();
mockMessageHandler.Protected()
.Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>())
.ReturnsAsync(new HttpResponseMessage
{
StatusCode = HttpStatusCode.OK,
Content = new StringContent(expected)
});
var httpClient = new HttpClient(mockMessageHandler.Object);
mockFactory.Setup(_ => _.CreateClient(It.IsAny<string>())).Returns(httpClient);
var logger = Mock.Of<ILogger<LoginController>>();
var controller = new LoginController(logger, mockFactory.Object);
return controller;
}
Source:
HttpConfiguration from System.Web.Http in .NET 5 project
For those looking to achieve the same result of utilising a mock IHttpClientFactory with the HttpClient delegate to avoid making calls to endpoints during testing and who are using a version of .NET Core higher than 2.2 (where it seems the Microsoft.AspNet.WebApi.Core package containing the HttpRequestMessageExtensions.CreateResponse extension is no longer available without relying upon the package targeting the .NET Core 2.2) then the below adaption of Nkosi's answer above has worked for me in .NET 5.
One can simply use an instance of HttpRequestMessage directly if that is all that is required.
public class HttpHandlerStubDelegate : DelegatingHandler
{
private readonly Func<HttpRequestMessage, CancellationToken, Task<HttpResponseMessage>> _handlerFunc;
public HttpHandlerStubDelegate()
{
_handlerFunc = (request, cancellationToken) => Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK));
}
public HttpHandlerStubDelegate(Func<HttpRequestMessage, CancellationToken, Task<HttpResponseMessage>> handlerFunc)
{
_handlerFunc = handlerFunc;
}
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
return _handlerFunc(request, cancellationToken);
}
}
As for the usage in the test Setup method, similarly, I've used an instance of HttpResponseMessage directly. In my case, the factoryMock is then passed into a custom Adapter which wraps around the HttpClient and is therefore set to use our fake HttpClient.
var expected = #"{ ""foo"": ""bar"" }";
var clientHandlerStub = new HttpHandlerStubDelegate((request, cancellationToken) => {
var response = new HttpResponseMessage() { StatusCode = HttpStatusCode.OK, Content = new StringContent(expected) };
return Task.FromResult(response);
});
var factoryMock = new Mock<IHttpClientFactory>();
factoryMock.Setup(m => m.CreateClient(It.IsAny<string>()))
.Returns(() => new HttpClient(clientHandlerStub));
And finally, an example NUnit test body using this which passes.
[Test]
public async Task Subject_Condition_Expectation()
{
var expected = #"{ ""foo"": ""bar"" }";
var result = await _myHttpClientWrapper.GetAsync("https://www.example.com/api/stuff");
var actual = await result.Content.ReadAsStringAsync();
Assert.AreEqual(expected, actual);
}
This code threw this exception for me,
System.InvalidOperationException: The request does not have an associated configuration object or the provided configuration was null.
So included this in the test method, and it works.
var configuration = new HttpConfiguration();
var request = new HttpRequestMessage();
request.SetConfiguration(configuration);
A different approach may be to create an extra class that will internally call the service. This class can be mocked easily.
It is not a direct answer to the question, but it seems a lot less complex and more testable.

C# Mock IHttpclient & CreateClient

I have a function that I want to x-unit test, but it seems that I have to mock the CreateClient function? Whenever I debug it during testing it seems that the var client is equals to null. I am injecting the dependencies properly, I am sure of that. What I want to know is how to mock the CreateClient.
here is that function:
public async Task CreateMessageHistoryAsync(Message message)
{
//This seems to be giving a null value
var client = this.clientFactory.CreateClient(NamedHttpClients.COUCHDB);
var formatter = new JsonMediaTypeFormatter();
formatter.SerializerSettings = new JsonSerializerSettings
{
Formatting = Formatting.Indented,
NullValueHandling = NullValueHandling.Ignore,
ContractResolver = new CamelCasePropertyNamesContractResolver()
};
Guid id = Guid.NewGuid();
var response = await client.PutAsync(id.ToString(), message, formatter);
if (!response.IsSuccessStatusCode)
{
throw new HttpRequestException(await response.Content.ReadAsStringAsync());
}
}
here is the unit test, I am mocking the IHttpClient in a separate class and I am using that class.
[Collection("MockStateCollection")]
public class CreateMessageHistory
{
private readonly MockStateFixture mockStateFixture;
public CreateMessageHistory(MockStateFixture mockStateFixture)
{
this.mockStateFixture = mockStateFixture;
}
[Fact]
public async Task Should_NotThrowHttpRequestException_When_AMessageHistoryIsCreated()
{
var recipients = MockMessage.GetRecipients("Acc", "Site 1", "Site 2", "Site 3");
var message = MockMessage.GetMessage(recipients);
mockStateFixture
.MockMessageHistoryService
.Setup(service => service.CreateMessageHistoryAsync(message));
var messageHistoryService = new MessageHistoryService(
mockStateFixture.MockIHttpClientFactory.Object);
mockStateFixture.MockIHttpClientFactory.Object.CreateClient("CouchDB");
var task = messageHistoryService.CreateMessageHistoryAsync(message);
var type = task.GetType();
Assert.True(type.GetGenericArguments()[0].Name == "VoidTaskResult");
Assert.True(type.BaseType == typeof(Task));
await task;
//await Assert.IsType<Task>(messageHistoryService.CreateMessageHistoryAsync(message));
// await Assert.ThrowsAsync<HttpRequestException>(() => messageHistoryService.CreateMessageHistoryAsync(message));
}
}
it seems to me that I also need to mock the CreateClient class is it?
You should inject a mocked object for ClientFactory for which you have setup the CreateClient method.
// create the mock client
var httpClient = new Mock<IHttpClient>();
// setup method call for client
httpClient.Setup(x=>x.PutAsync(It.IsAny<string>()
, It.IsAny<Message>(),
, It.IsAny< JsonMediaTypeFormatter>())
.Returns(Task.FromResult(new HttpResponseMessage { StatusCode = StatusCode.OK}));
// create the mock client factory mock
var httpClientFactoryMock = new Mock<IHttpClientFactory>();
// setup the method call
httpClientFactoryMock.Setup(x=>x.CreateClient(NamedHttpClients.COUCHDB))
.Returns(httpClient);
Then you have to pass the httpClientFactoryMock.Object to the constructor:
var messageHistoryService = new MessageHistoryService(httpClientFactoryMock.Object);
Update
In order to unit test HttpClient since it hasn't any interface you should wrap it in way as it is described here.
Specifically we have to arrange the http client as below:
// Mock the handler
var handlerMock = new Mock<HttpMessageHandler>(MockBehavior.Strict);
handlerMock.Protected()
// Setup the PROTECTED method to mock
.Setup<Task<HttpResponseMessage>>("PutAsync",
ItExpr.IsAny<String>(),
ItExpr.IsAny<Message>()
ItExpr.IsAny<MediaTypeFormatter>())
// prepare the expected response of the mocked http call
.ReturnsAsync(new HttpResponseMessage()
{
StatusCode = HttpStatusCode.OK
})
.Verifiable();
// use real http client with mocked handler here
var httpClient = new HttpClient(handlerMock.Object)
{
BaseAddress = new Uri("http://test.com/"),
};
Now we should return the above httpClient when CreateClient is called.
// create the mock client factory mock
var httpClientFactoryMock = new Mock<IHttpClientFactory>();
// setup the method call
httpClientFactoryMock.Setup(x=>x.CreateClient(NamedHttpClients.COUCHDB))
.Returns(httpClient);

How can I test a custom DelegatingHandler in the ASP.NET MVC 4 Web API?

I've seen this question come up in a few places, and not seen any great answers. As I've had to do this myself a few times, I thought I'd post my solution. If you have anything better, please post.
N.B. This is using ASP.NET MVC 4 Beta 2 version of Web API - future versions may change!
Update: This still works in ASP.NET MVC 4 RC
In this approach, I create a TestHandler and set it as the InnerHandler property of the handler under test.
The handler under test can then be passed to an HttpClient - this may seem unintuitive if you are writing a server-side handler, but this is actually a great light-weight way to test a handler - it will be called in the same way it would in a server.
The TestHandler will just return an HTTP 200 by default, but it's constructor accepts a function you can use to make asserts about the request message passed
in from the handler under test. Finally you can make asserts on the result of the SendAsync call from the client.
Once everything is set up, call SendAsync on the client instance to invoke your handler. The request will be passed into your handler, it will pass this on to the TestHandler (assuming it passes the call on) which will then return a response back to your handler.
The test handler looks like this:
public class TestHandler : DelegatingHandler
{
private readonly Func<HttpRequestMessage,
CancellationToken, Task<HttpResponseMessage>> _handlerFunc;
public TestHandler()
{
_handlerFunc = (r, c) => Return200();
}
public TestHandler(Func<HttpRequestMessage,
CancellationToken, Task<HttpResponseMessage>> handlerFunc)
{
_handlerFunc = handlerFunc;
}
protected override Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
return _handlerFunc(request, cancellationToken);
}
public static Task<HttpResponseMessage> Return200()
{
return Task.Factory.StartNew(
() => new HttpResponseMessage(HttpStatusCode.OK));
}
}
Example usage with an imagined MyHandler under test. Uses NUnit for the asserts.:
var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, "http://test.com");
httpRequestMessage.Headers.Add("username", "test");
var handler = new MyHandler()
{
InnerHandler = new TestHandler((r,c) =>
{
Assert.That(r.Headers.Contains("username"));
return TestHandler.Return200();
})
};
var client = new HttpClient(handler);
var result = client.SendAsync(httpRequestMessage).Result;
Assert.That(result.StatusCode, Is.EqualTo(HttpStatusCode.OK));
The default behaviour of TestHandler is probably fine for many tests and makes the code simpler. The setup of the handler under test then looks like this:
var handler = new MyHandler();
handler.InnerHandler = new TestHandler();
I like this approach because it keeps all the assertions in the test method, and the TestHandler is very reusable.
I was just looking for the same thing but came up with a more concise approach that didn't use http client. I wanted a test to assert the message handler consumed a mocked logging component. I didn't really need the inner handler to function, just to "stub" it out to satisfy the unit test. Works for my purpose :)
//ARRANGE
var logger = new Mock<ILogger>();
var handler= new ServiceLoggingHandler(logger.Object);
var request = ControllerContext.CreateHttpRequest(Guid.NewGuid(), "http://test",HttpMethod.Get);
handler.InnerHandler = new Mock<HttpMessageHandler>(MockBehavior.Loose).Object;
request.Content = new ObjectContent<CompanyRequest>(Company.CreateCompanyDTO(), new JsonMediaTypeFormatter());
var invoker = new HttpMessageInvoker(handler);
//ACT
var result = invoker.SendAsync(request, new System.Threading.CancellationToken()).Result;
//ASSERT
<Your assertion>
I also found this answer because i have my custom handler and i want to test it
We are using NUnit and Moq, so i think my solution can be helpful for someone
using Moq;
using Moq.Protected;
using NUnit.Framework;
namespace Unit.Tests
{
[TestFixture]
public sealed class Tests1
{
private HttpClient _client;
private HttpRequestMessage _httpRequest;
private Mock<DelegatingHandler> _testHandler;
private MyCustomHandler _subject;//MyCustomHandler inherits DelegatingHandler
[SetUp]
public void Setup()
{
_httpRequest = new HttpRequestMessage(HttpMethod.Get, "/someurl");
_testHandler = new Mock<DelegatingHandler>();
_subject = new MyCustomHandler // create subject
{
InnerHandler = _testHandler.Object //initialize InnerHandler with our mock
};
_client = new HttpClient(_subject)
{
BaseAddress = new Uri("http://localhost")
};
}
[Test]
public async Task Given_1()
{
var mockedResult = new HttpResponseMessage(HttpStatusCode.Accepted);
void AssertThatRequestCorrect(HttpRequestMessage request, CancellationToken token)
{
Assert.That(request, Is.SameAs(_httpRequest));
//... Other asserts
}
// setup protected SendAsync
// our MyCustomHandler will call SendAsync internally, and we want to check this call
_testHandler
.Protected()
.Setup<Task<HttpResponseMessage>>("SendAsync", _httpRequest, ItExpr.IsAny<CancellationToken>())
.Callback(
(Action<HttpRequestMessage, CancellationToken>)AssertThatRequestCorrect)
.ReturnsAsync(mockedResult);
//Act
var actualResponse = await _client.SendAsync(_httpRequest);
//check that internal call to SendAsync was only Once and with proper request object
_testHandler
.Protected()
.Verify("SendAsync", Times.Once(), _httpRequest, ItExpr.IsAny<CancellationToken>());
// if our custom handler modifies somehow our response we can check it here
Assert.That(actualResponse.IsSuccessStatusCode, Is.True);
Assert.That(actualResponse, Is.EqualTo(mockedResult));
//...Other asserts
}
}
}
I created the following for testing DelegatingHandlers. It is useful for handlers that use the HttpRequestMessage.DependencyScope to resolve dependencies using your favorite IoC framework e.g. a WindsorDependencyResolver with a WindsorContainer:
public class UnitTestHttpMessageInvoker : HttpMessageInvoker
{
private readonly HttpConfiguration configuration;
public UnitTestHttpMessageInvoker(HttpMessageHandler handler, IDependencyResolver resolver)
: base(handler, true)
{
this.configuration = new HttpConfiguration();
configuration.DependencyResolver = resolver;
}
[DebuggerNonUserCode]
public override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
if (request == null)
{
throw new ArgumentNullException("request");
}
request.Properties["MS_HttpConfiguration"] = this.configuration;
return base.SendAsync(request, cancellationToken);
}
}
Another alternative could be stubbing
public class TestingHandlerStub : DelegatingHandler
{
private readonly Func<HttpRequestMessage, CancellationToken, Task<HttpResponseMessage>> _handlerFunc;
public TestingHandlerStub(Func<HttpRequestMessage, CancellationToken, Task<HttpResponseMessage>> handlerFunc)
{
_handlerFunc = handlerFunc;
}
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
return _handlerFunc(request, cancellationToken);
}
}
And this is how to combine :
var handler = new YourCustomHandler()
{
InnerHandler = new TestingHandlerStub((r, c) =>
{
return Task.FromResult(httpResponseMessage);
})
};
var client = new HttpClient(handler);

Categories

Resources