How to Unit Test method that uses a Webservice on Windows Phone? - c#

I'm working on a project that retrieves information from an external webservice API, but I'm not sure how I'm supposed to test it, I'm quite new at Testing and I have done just a couple of Unit Test, but as far as I know I have to mock the webservice functionality, I've been looking for info regarding this subject but haven't found anything for Windows Phone yet. What's the standard procedure for these type of cases?
Here's a simple version of what I want to test:
public async Task<List<Song>> FetchSongsAsync(String query)
{
if (String.IsNullOrEmpty(query))
return null;
string requestUrl = "webservice url";
var client = new HttpClient();
var result = await client.GetStringAsync(new Uri(requestUrl,UriKind.Absolute));
try
{
var result = JsonConvert.DeserializeObject<RootObject>(result);
return result;
}
catch (Exception)
{
return null;
}
}
Thanks!

Decouple your code from its dependencies: make content loading and its deserialization replaceable:
private readonly IClient client;
private readonly ISerializer serializer;
public YourService(IClient client, ISerializer serializer)
{
_client = client;
_serializer = serializer;
}
public async Task<List<Song>> FetchSongsAsync(String query)
{
try
{
var result = await _client.GetStringAsync(new Uri("http://example.com"));
return _serializer.DeserializeObject<RootObject>(result);
}
catch (Exception)
{
return null;
}
}

The first thing that may help is understand and use dependency injection. Basically taking any dependencies of your object/method/etc and (as it states) injecting them into the object/method/etc. For example, you are having a difficult time figuring out how to test the method because the method depends on being able to access the web service. There are a couple things you can do after this.
One thing to do is to check out mocking frameworks such as Moq.
Another thing I recently did was I added an overloaded constructor (dependency injection) that takes a HttpMessageInvoker object (note HttpClient derives from this). This way I could instantiate the class with my own response message:
public class MyLoader()
{
protected HttpMessageInvoker MessageInvoker { get; set; }
private HttpRequestMessage requestMessage;
public MyLoader() // default constructor
{
MessageInvoker = new HttpClient();
}
public MyLoader(HttpMessageInvoker httpMessageInvoker)
{
MessageInvoker = httpMessageInvoker;
}
public object DoSomething()
{
var response = await MessageInvoker.SendAsync(requestMessage, cancellationTokenSource.Token);
}
Here is my mock message invoker:
public class MockMessageInvoker : HttpMessageInvoker
{
public string ResponseString { get; set; }
public MockMessageInvoker(string responseString)
: base(new HttpClientHandler())
{
ResponseString = responseString;
}
public override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
{
return Task.Run<HttpResponseMessage>(() =>
{
HttpResponseMessage responseMessage = new HttpResponseMessage(
System.Net.HttpStatusCode.OK);
var bytes = Encoding.ASCII.GetBytes(ResponseString);
var stream = new System.IO.MemoryStream(bytes);
responseMessage.Content = new StreamContent(stream);
return responseMessage;
});
}
}
I can call it all like so:
MyLoader loader = new MyLoader(new MockMessageInvoker(validJsonResponse));
loader.DoSomething() // I've removed the dependency on the service and have control of the content in the response
It's quick and dirty, but does the trick.
Hope this helps.

Related

How to mock a method that depends on HttpClient? [duplicate]

I have some issues trying to wrap my code to be used in unit tests. The issues is this. I have the interface IHttpHandler:
public interface IHttpHandler
{
HttpClient client { get; }
}
And the class using it, HttpHandler:
public class HttpHandler : IHttpHandler
{
public HttpClient client
{
get
{
return new HttpClient();
}
}
}
And then the Connection class, which uses simpleIOC to inject the client implementation:
public class Connection
{
private IHttpHandler _httpClient;
public Connection(IHttpHandler httpClient)
{
_httpClient = httpClient;
}
}
And then I have a unit test project which has this class:
private IHttpHandler _httpClient;
[TestMethod]
public void TestMockConnection()
{
var client = new Connection(_httpClient);
client.doSomething();
// Here I want to somehow create a mock instance of the http client
// Instead of the real one. How Should I approach this?
}
Now obviously I will have methods in the Connection class that will retrieve data (JSON) from my backend. However, I want to write unit tests for this class, and obviously I don't want to write tests against the real back end, rather a mocked one. I have tried to google a good answer to this without great success. I can and have used Moq to mock before, but never on something like HttpClient. How should I approach this problem?
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.
If you'd prefer a DSL to using Moq, I have a library up on GitHub/Nuget that makes things a little easier: https://github.com/richardszalay/mockhttp
The Nuget Package RichardSzalay.MockHttp is available here.
var mockHttp = new MockHttpMessageHandler();
// Setup a respond for the user api (including a wildcard in the URL)
mockHttp.When("http://localhost/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://localhost/api/user/1234");
// or without async: var response = client.GetAsync("http://localhost/api/user/1234").Result;
var json = await response.Content.ReadAsStringAsync();
// No network connection required
Console.Write(json); // {'name' : 'Test McGee'}
I agree with some of the other answers that the best approach is to mock the HttpMessageHandler inside HttpClient, rather than wrap HttpClient. This answer is unique in that it still injects HttpClient, allowing it to be a singleton or managed with dependency injection.
HttpClient is intended to be instantiated once and re-used throughout
the life of an application.
(Source).
Mocking HttpMessageHandler can be a little tricky because SendAsync is protected. Here's a complete example, using xunit and Moq.
using System;
using System.Net;
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
using Moq;
using Moq.Protected;
using Xunit;
// Use nuget to install xunit and Moq
namespace MockHttpClient {
class Program {
static void Main(string[] args) {
var analyzer = new SiteAnalyzer(Client);
var size = analyzer.GetContentSize("http://microsoft.com").Result;
Console.WriteLine($"Size: {size}");
}
private static readonly HttpClient Client = new HttpClient(); // Singleton
}
public class SiteAnalyzer {
public SiteAnalyzer(HttpClient httpClient) {
_httpClient = httpClient;
}
public async Task<int> GetContentSize(string uri)
{
var response = await _httpClient.GetAsync( uri );
var content = await response.Content.ReadAsStringAsync();
return content.Length;
}
private readonly HttpClient _httpClient;
}
public class SiteAnalyzerTests {
[Fact]
public async void GetContentSizeReturnsCorrectLength() {
// Arrange
const string testContent = "test content";
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(testContent)
});
var underTest = new SiteAnalyzer(new HttpClient(mockMessageHandler.Object));
// Act
var result = await underTest.GetContentSize("http://anyurl");
// Assert
Assert.Equal(testContent.Length, result);
}
}
}
Your interface exposes the concrete HttpClient class, therefore any classes that use this interface are tied to it, this means that it cannot be mocked.
HttpClient does not inherit from any interface so you will have to write your own. I suggest a decorator-like pattern:
public interface IHttpHandler
{
HttpResponseMessage Get(string url);
HttpResponseMessage Post(string url, HttpContent content);
Task<HttpResponseMessage> GetAsync(string url);
Task<HttpResponseMessage> PostAsync(string url, HttpContent content);
}
And your class will look like this:
public class HttpClientHandler : IHttpHandler
{
private HttpClient _client = new HttpClient();
public HttpResponseMessage Get(string url)
{
return GetAsync(url).Result;
}
public HttpResponseMessage Post(string url, HttpContent content)
{
return PostAsync(url, content).Result;
}
public async Task<HttpResponseMessage> GetAsync(string url)
{
return await _client.GetAsync(url);
}
public async Task<HttpResponseMessage> PostAsync(string url, HttpContent content)
{
return await _client.PostAsync(url, content);
}
}
The point in all of this is that HttpClientHandler creates its own HttpClient, you could then of course create multiple classes that implement IHttpHandler in different ways.
The main issue with this approach is that you are effectively writing a class that just calls methods in another class, however you could create a class that inherits from HttpClient (See Nkosi's example, it's a much better approach than mine). Life would be much easier if HttpClient had an interface that you could mock, unfortunately it does not.
This example is not the golden ticket however. IHttpHandler still relies on HttpResponseMessage, which belongs to System.Net.Http namespace, therefore if you do need other implementations other than HttpClient, you will have to perform some kind of mapping to convert their responses into HttpResponseMessage objects. This of course is only a problem if you need to use multiple implementations of IHttpHandler but it doesn't look like you do so it's not the end of the world, but it's something to think about.
Anyway, you can simply mock IHttpHandler without having to worry about the concrete HttpClient class as it has been abstracted away.
I recommend testing the non-async methods, as these still call the asynchronous methods but without the hassle of having to worry about unit testing asynchronous methods, see here
This is a common question, and I was heavily on the side wanting the ability to mock HttpClient, but I think I finally came to the realization that you shouldn't be mocking HttpClient. It seems logical to do so, but I think we've been brainwashed by things we see in open source libraries.
We often see "Clients" out there that we mock in our code so that we can test in isolation, so we automatically try to apply the same principle to HttpClient. HttpClient actually does a lot; you can think of it as a manager for HttpMessageHandler, so you don't wanna mock that, and that's why it still doesn't have an interface. The part that you're really interested in for unit testing, or designing your services, even, is the HttpMessageHandler since that is what returns the response, and you can mock that.
It's also worth pointing out that you should probably start treating HttpClient like a bigger deal. For example: Keep your instatiating of new HttpClients to a minimum. Reuse them, they're designed to be reused and use a crap ton less resources if you do. If you start treating it like a bigger deal, it'll feel much more wrong wanting to mock it and now the message handler will start to be the thing that you're injecting, not the client.
In other words, design your dependencies around the handler instead of the client. Even better, abstract "services" that use HttpClient which allow you to inject a handler, and use that as your injectable dependency instead. In fact, HttpClientFactor (which you should be using) is designed with extensions to inject the message handlers. Then in your tests, you can fake the handler to control the response for setting up your tests.
Wrapping HttpClient is an insane waste of time.
Update:
See Joshua Dooms's example. It's exactly what I'm recommending.
Here's a simple solution, which worked well for me.
Using the moq mocking library.
// ARRANGE
var handlerMock = new Mock<HttpMessageHandler>(MockBehavior.Strict);
handlerMock
.Protected()
// Setup the PROTECTED method to mock
.Setup<Task<HttpResponseMessage>>(
"SendAsync",
ItExpr.IsAny<HttpRequestMessage>(),
ItExpr.IsAny<CancellationToken>()
)
// prepare the expected response of the mocked http call
.ReturnsAsync(new HttpResponseMessage()
{
StatusCode = HttpStatusCode.OK,
Content = new StringContent("[{'id':1,'value':'1'}]"),
})
.Verifiable();
// use real http client with mocked handler here
var httpClient = new HttpClient(handlerMock.Object)
{
BaseAddress = new Uri("http://test.com/"),
};
var subjectUnderTest = new MyTestClass(httpClient);
// ACT
var result = await subjectUnderTest
.GetSomethingRemoteAsync('api/test/whatever');
// ASSERT
result.Should().NotBeNull(); // this is fluent assertions here...
result.Id.Should().Be(1);
// also check the 'http' call was like we expected it
var expectedUri = new Uri("http://test.com/api/test/whatever");
handlerMock.Protected().Verify(
"SendAsync",
Times.Exactly(1), // we expected a single external request
ItExpr.Is<HttpRequestMessage>(req =>
req.Method == HttpMethod.Get // we expected a GET request
&& req.RequestUri == expectedUri // to this uri
),
ItExpr.IsAny<CancellationToken>()
);
Source: https://gingter.org/2018/07/26/how-to-mock-httpclient-in-your-net-c-unit-tests/
Building on the other answers, I suggest this code, which does not have any outside dependencies:
[TestClass]
public class MyTestClass
{
[TestMethod]
public async Task MyTestMethod()
{
var httpClient = new HttpClient(new MockHttpMessageHandler());
var content = await httpClient.GetStringAsync("http://some.fake.url");
Assert.AreEqual("Content as string", content);
}
}
public class MockHttpMessageHandler : HttpMessageHandler
{
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request,
CancellationToken cancellationToken)
{
var responseMessage = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StringContent("Content as string")
};
return await Task.FromResult(responseMessage);
}
}
As also mentioned in the comments you need to abstract away the HttpClient so as not to be coupled to it. I've done something similar in the past. I'll try to adapt what I did with what you are trying to do.
First look at the HttpClient class and decided on what functionality it provided that would be needed.
Here is a possibility:
public interface IHttpClient {
System.Threading.Tasks.Task<T> DeleteAsync<T>(string uri) where T : class;
System.Threading.Tasks.Task<T> DeleteAsync<T>(Uri uri) where T : class;
System.Threading.Tasks.Task<T> GetAsync<T>(string uri) where T : class;
System.Threading.Tasks.Task<T> GetAsync<T>(Uri uri) where T : class;
System.Threading.Tasks.Task<T> PostAsync<T>(string uri, object package);
System.Threading.Tasks.Task<T> PostAsync<T>(Uri uri, object package);
System.Threading.Tasks.Task<T> PutAsync<T>(string uri, object package);
System.Threading.Tasks.Task<T> PutAsync<T>(Uri uri, object package);
}
Again as stated before this was for particular purposes. I completely abstracted away most dependencies to anything dealing with HttpClient and focused on what I wanted returned. You should evaluate how you want to abstract the HttpClient to provide only the necessary functionality you want.
This will now allow you to mock only what is needed to be tested.
I would even recommend doing away with IHttpHandler completely and use the HttpClient abstraction IHttpClient. But I'm just not picking as you can replace the body of your handler interface with the members of the abstracted client.
An implementation of the IHttpClient can then be used to wrapp/adapt a real/concrete HttpClient or any other object for that matter, that can be used to make HTTP requests as what you really wanted was a service that provided that functionality as apposed to HttpClient specifically. Using the abstraction is a clean (My opinion) and SOLID approach and can make your code more maintainable if you need to switch out the underlying client for something else as the framework changes.
Here is a snippet of how an implementation could be done.
/// <summary>
/// HTTP Client adaptor wraps a <see cref="System.Net.Http.HttpClient"/>
/// that contains a reference to <see cref="ConfigurableMessageHandler"/>
/// </summary>
public sealed class HttpClientAdaptor : IHttpClient {
HttpClient httpClient;
public HttpClientAdaptor(IHttpClientFactory httpClientFactory) {
httpClient = httpClientFactory.CreateHttpClient(**Custom configurations**);
}
//...other code
/// <summary>
/// Send a GET request to the specified Uri as an asynchronous operation.
/// </summary>
/// <typeparam name="T">Response type</typeparam>
/// <param name="uri">The Uri the request is sent to</param>
/// <returns></returns>
public async System.Threading.Tasks.Task<T> GetAsync<T>(Uri uri) where T : class {
var result = default(T);
//Try to get content as T
try {
//send request and get the response
var response = await httpClient.GetAsync(uri).ConfigureAwait(false);
//if there is content in response to deserialize
if (response.Content.Headers.ContentLength.GetValueOrDefault() > 0) {
//get the content
string responseBodyAsText = await response.Content.ReadAsStringAsync().ConfigureAwait(false);
//desrialize it
result = deserializeJsonToObject<T>(responseBodyAsText);
}
} catch (Exception ex) {
Log.Error(ex);
}
return result;
}
//...other code
}
As you can see in the above example, a lot of the heavy lifting usually associated with using HttpClient is hidden behind the abstraction.
You connection class can then be inject with the abstracted client
public class Connection
{
private IHttpClient _httpClient;
public Connection(IHttpClient httpClient)
{
_httpClient = httpClient;
}
}
Your test can then mock what is needed for your SUT
private IHttpClient _httpClient;
[TestMethod]
public void TestMockConnection()
{
SomeModelObject model = new SomeModelObject();
var httpClientMock = new Mock<IHttpClient>();
httpClientMock.Setup(c => c.GetAsync<SomeModelObject>(It.IsAny<string>()))
.Returns(() => Task.FromResult(model));
_httpClient = httpClientMock.Object;
var client = new Connection(_httpClient);
// Assuming doSomething uses the client to make
// a request for a model of type SomeModelObject
client.doSomething();
}
I think the issue is that you've got it just a little upside down.
public class AuroraClient : IAuroraClient
{
private readonly HttpClient _client;
public AuroraClient() : this(new HttpClientHandler())
{
}
public AuroraClient(HttpMessageHandler messageHandler)
{
_client = new HttpClient(messageHandler);
}
}
If you look at the class above, I think this is what you want. Microsoft recommends keeping the client alive for optimal performance, so this type of structure allows you to do that. Also the HttpMessageHandler is an abstract class and therefore mockable. Your test method would then look like this:
[TestMethod]
public void TestMethod1()
{
// Arrange
var mockMessageHandler = new Mock<HttpMessageHandler>();
// Set up your mock behavior here
var auroraClient = new AuroraClient(mockMessageHandler.Object);
// Act
// Assert
}
This allows you to test your logic while mocking the HttpClient's behavior.
Sorry guys, after writing this and trying it myself, I realized that you can't mock the protected methods on the HttpMessageHandler. I subsequently added the following code to allow for injection of a proper mock.
public interface IMockHttpMessageHandler
{
Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken);
}
public class MockHttpMessageHandler : HttpMessageHandler
{
private readonly IMockHttpMessageHandler _realMockHandler;
public MockHttpMessageHandler(IMockHttpMessageHandler realMockHandler)
{
_realMockHandler = realMockHandler;
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
return await _realMockHandler.SendAsync(request, cancellationToken);
}
}
The tests written with this then look something like the following:
[TestMethod]
public async Task GetProductsReturnsDeserializedXmlXopData()
{
// Arrange
var mockMessageHandler = new Mock<IMockHttpMessageHandler>();
// Set up Mock behavior here.
var client = new AuroraClient(new MockHttpMessageHandler(mockMessageHandler.Object));
// Act
// Assert
}
One alternative would be to setup a stub HTTP server that returns canned responses based on pattern matching the request url, meaning you test real HTTP requests not mocks. Historically this would have taken significant develoment effort and would have been far to slow to be considered for unit testing, however OSS library WireMock.net is easy to use and fast enough to be run with lots of tests so may be worth considering. Setup is a few lines of code:
var server = FluentMockServer.Start();
server.Given(
Request.Create()
.WithPath("/some/thing").UsingGet()
)
.RespondWith(
Response.Create()
.WithStatusCode(200)
.WithHeader("Content-Type", "application/json")
.WithBody("{'attr':'value'}")
);
You can find a more details and guidance on using wiremock in tests here.
One of my colleagues noticed that most of the HttpClient methods all call SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) under the hood, which is a virtual method off of HttpMessageInvoker:
So by far the easiest way to mock out HttpClient was to simply mock that particular method:
var mockClient = new Mock<HttpClient>();
mockClient.Setup(client => client.SendAsync(It.IsAny<HttpRequestMessage>(), It.IsAny<CancellationToken>())).ReturnsAsync(_mockResponse.Object);
and your code can call most (but not all) of the HttpClient class methods, including a regular
httpClient.SendAsync(req)
Check here to confirm
https://github.com/dotnet/corefx/blob/master/src/System.Net.Http/src/System/Net/Http/HttpClient.cs
Microsoft now offers the alternative to use a IHttpClientFactory instead of directly using HttpClient:
https://learn.microsoft.com/en-us/aspnet/core/fundamentals/http-requests?view=aspnetcore-5.0
Example Mock with request that returns expected result:
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:
https://stackoverflow.com/a/66256132/3850405
I'm not convinced by many of the answers.
First of all, imagine you want to unit test a method that uses HttpClient. You should not instantiate HttpClient directly in your implementation. You should inject a factory with the responsibility of providing an instance of HttpClient for you. That way you can mock later on that factory and return whichever HttpClient you want (e.g: a mock HttpClient and not the real one).
So, you would have a factory like the following:
public interface IHttpClientFactory
{
HttpClient Create();
}
And an implementation:
public class HttpClientFactory
: IHttpClientFactory
{
public HttpClient Create()
{
var httpClient = new HttpClient();
return httpClient;
}
}
Of course you would need to register in your IoC Container this implementation. If you use Autofac it would be something like:
builder
.RegisterType<IHttpClientFactory>()
.As<HttpClientFactory>()
.SingleInstance();
Now you would have a proper and testeable implementation. Imagine that your method is something like:
public class MyHttpClient
: IMyHttpClient
{
private readonly IHttpClientFactory _httpClientFactory;
public SalesOrderHttpClient(IHttpClientFactory httpClientFactory)
{
_httpClientFactory = httpClientFactory;
}
public async Task<string> PostAsync(Uri uri, string content)
{
using (var client = _httpClientFactory.Create())
{
var clientAddress = uri.GetLeftPart(UriPartial.Authority);
client.BaseAddress = new Uri(clientAddress);
var content = new StringContent(content, Encoding.UTF8, "application/json");
var uriAbsolutePath = uri.AbsolutePath;
var response = await client.PostAsync(uriAbsolutePath, content);
var responseJson = response.Content.ReadAsStringAsync().Result;
return responseJson;
}
}
}
Now the testing part. HttpClient extends HttpMessageHandler, which is abstract. Let's create a "mock" of HttpMessageHandler that accepts a delegate so that when we use the mock we can also setup each behaviour for each test.
public class MockHttpMessageHandler
: HttpMessageHandler
{
private readonly Func<HttpRequestMessage, CancellationToken, Task<HttpResponseMessage>> _sendAsyncFunc;
public MockHttpMessageHandler(Func<HttpRequestMessage, CancellationToken, Task<HttpResponseMessage>> sendAsyncFunc)
{
_sendAsyncFunc = sendAsyncFunc;
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
return await _sendAsyncFunc.Invoke(request, cancellationToken);
}
}
And now, and with the help of Moq (and FluentAssertions, a library that makes unit tests more readable), we have everything needed to unit test our method PostAsync that uses HttpClient
public static class PostAsyncTests
{
public class Given_A_Uri_And_A_JsonMessage_When_Posting_Async
: Given_WhenAsync_Then_Test
{
private SalesOrderHttpClient _sut;
private Uri _uri;
private string _content;
private string _expectedResult;
private string _result;
protected override void Given()
{
_uri = new Uri("http://test.com/api/resources");
_content = "{\"foo\": \"bar\"}";
_expectedResult = "{\"result\": \"ok\"}";
var httpClientFactoryMock = new Mock<IHttpClientFactory>();
var messageHandlerMock =
new MockHttpMessageHandler((request, cancellation) =>
{
var responseMessage =
new HttpResponseMessage(HttpStatusCode.Created)
{
Content = new StringContent("{\"result\": \"ok\"}")
};
var result = Task.FromResult(responseMessage);
return result;
});
var httpClient = new HttpClient(messageHandlerMock);
httpClientFactoryMock
.Setup(x => x.Create())
.Returns(httpClient);
var httpClientFactory = httpClientFactoryMock.Object;
_sut = new SalesOrderHttpClient(httpClientFactory);
}
protected override async Task WhenAsync()
{
_result = await _sut.PostAsync(_uri, _content);
}
[Fact]
public void Then_It_Should_Return_A_Valid_JsonMessage()
{
_result.Should().BeEquivalentTo(_expectedResult);
}
}
}
Obviously this test is silly, and we're really testing our mock. But you get the idea. You should test meaningful logic depending on your implementation such as..
if the code status of the response is not 201, should it throw an exception?
if the response text cannot be parsed, what should happen?
etc.
The purpose of this answer was to test something that uses HttpClient and this is a nice clean way to do so.
UPDATE
Lately I use an http builder in my tests where I can easily inject the json response I expect.
public class HttpClientBuilder
{
private HttpMessageHandler _httpMessageHandler = new HttpClientHandler();
public HttpClientBuilder WithJsonResponse(HttpStatusCode httpStatusCode, string json, string contentType = "application/json")
{
var mockHttpMessageHandler =
new MockHttpMessageHandler(
(request, cancellation) =>
{
var responseMessage =
new HttpResponseMessage(httpStatusCode)
{
Content = new StringContent(json, Encoding.UTF8, contentType)
};
var result = Task.FromResult(responseMessage);
return result;
});
_httpMessageHandler = mockHttpMessageHandler;
return this;
}
public HttpClient Build()
{
var httpClient = new HttpClient(_httpMessageHandler);
return httpClient;
}
}
class MockHttpMessageHandler
: HttpMessageHandler
{
private readonly Func<HttpRequestMessage, CancellationToken, Task<HttpResponseMessage>> _sendAsyncFunc;
public MockHttpMessageHandler(Func<HttpRequestMessage, CancellationToken, Task<HttpResponseMessage>> sendAsyncFunc)
{
_sendAsyncFunc = sendAsyncFunc;
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
return await _sendAsyncFunc.Invoke(request, cancellationToken);
}
}
so, as long as I have the HttpClient behind an abstraction like IHttpClientFactory, as I've suggested above, in my tests I can do something like
var httpClientFactoryMock = new Mock<IHttpClientFactory>();
var jsonResponse = "{\"hello world\"}";
var httpClient =
new HttpClientBuilder()
.WithJsonResponse(HttpStatusCode.OK, jsonResponse)
.Build();
httpClientFactoryMock
.Setup(x => x.Create())
.Returns(httpClient);
var httpClientFactory = httpClientFactoryMock.Object;
and then use that httpClientFactory.
DO NOT have a wrapper that creates a new instance of HttpClient. If you do that, you will run out of sockets at runtime (even though you are disposing the HttpClient object).
If using MOQ, the correct way to do this is to add using Moq.Protected; to your test and then write code like the following:
var response = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StringContent("It worked!")
};
var mockHttpMessageHandler = new Mock<HttpMessageHandler>();
mockHttpMessageHandler
.Protected()
.Setup<Task<HttpResponseMessage>>(
"SendAsync",
ItExpr.IsAny<HttpRequestMessage>(),
ItExpr.IsAny<CancellationToken>())
.ReturnsAsync(() => response);
var httpClient = new HttpClient(mockHttpMessageHandler.Object);
Joining the party a bit late, but I like using wiremocking (https://github.com/WireMock-Net/WireMock.Net) whenever possible in the integrationtest of a dotnet core microservice with downstream REST dependencies.
By implementing a TestHttpClientFactory extending the IHttpClientFactory we can override the method
HttpClient CreateClient(string name)
So when using the named clients within your app you are in control of returning a HttpClient wired to your wiremock.
The good thing about this approach is that you are not changing anything within the application you are testing, and enables course integration tests doing an actual REST request to your service and mocking the json (or whatever) the actual downstream request should return. This leads to concise tests and as little mocking as possible in your application.
public class TestHttpClientFactory : IHttpClientFactory
{
public HttpClient CreateClient(string name)
{
var httpClient = new HttpClient
{
BaseAddress = new Uri(G.Config.Get<string>($"App:Endpoints:{name}"))
// G.Config is our singleton config access, so the endpoint
// to the running wiremock is used in the test
};
return httpClient;
}
}
and
// in bootstrap of your Microservice
IHttpClientFactory factory = new TestHttpClientFactory();
container.Register<IHttpClientFactory>(factory);
There are several different approaches to mock an HttpClient. Here are a few that I've done some POC's on using xUnit before deciding on a single solution (Moq.Contrib.HttpClient). Note that there are many more abilities to each framework than what I show below; I kept each example succinct for clarity.
Moq (by itself)
This is relatively straightforward if you are familiar with using the Moq framework. The "trick" is to mock the HttpMessageHandler inside of the HttpClient - not the HttpClient itself. NOTE: It is good practice to use MockBehavior.Strict in the mock so that you are alerted to any calls that you have not explicitly mocked-out and were expecting.
RichardSzalay.MockHttp
RichardSzalay.MockHttp is another popular solution. I've used this in the past but found it slightly more cumbersome that Moq.Contrib.HttpClient. There are two different patterns that can be used here. Richard describes when to use one vs the other here.
Moq.Contrib.HttpClient
Like the solution for using Moq by itself, this is straightforward if you are familiar with using the Moq framework. I found this solution to be slightly more direct with less code. This is the solution I opted to use. Note that this solution requires a separate Nuget from Moq itself - Moq.Contrib.HttpClient
WireMock.Net
A newcomer to the game, WireMock.net is gaining popularity. This would be a reasonable solution instead of Microsoft.AspNetCore.TestHost if you are writing Integration Tests where calls to the endpoint are actually made instead of being mocked. I thought this would be my pick at first but decided against it for two reasons:
it does actually open ports to facilitate the test. Since I've had to fix port-exhaustion issues from improper usage of HttpClient in the past, I decided to pass on this solution as I wasn't sure how well it would scale across a large codebase with many unit tests running in parallel.
The urls used must be resolvable (actual legit urls). If you want the simplicity of not caring about a "real" url (just that the url you expected was actually called) then this may not be for you.
Example
Given the following simplistic/contrived code, here is how you would write each test.
public class ClassUnderTest
{
private readonly HttpClient _httpClient;
private const string Url = "https://myurl";
public ClassUnderTest(HttpClient httpClient)
{
_httpClient = httpClient;
}
public async Task<Person> GetPersonAsync(int id)
{
var response = await _httpClient.GetAsync($"{Url}?id={id}");
return await response.Content.ReadFromJsonAsync<Person>();
}
}
public class Person
{
public int Id { get; set; }
public string Name { get; set; }
public int Age { get; set; }
}
Moq (by itself)
[Fact]
public async Task JustMoq()
{
//arrange
const int personId = 1;
var mockHandler = new Mock<HttpMessageHandler>(MockBehavior.Strict);
var dto = new Person { Id = personId, Name = "Dave", Age = 42 };
var mockResponse = new HttpResponseMessage
{
StatusCode = HttpStatusCode.OK,
Content = JsonContent.Create<Person>(dto)
};
mockHandler
.Protected()
.Setup<Task<HttpResponseMessage>>(
"SendAsync",
ItExpr.Is<HttpRequestMessage>(m => m.Method == HttpMethod.Get),
ItExpr.IsAny<CancellationToken>())
.ReturnsAsync(mockResponse);
// Inject the handler or client into your application code
var httpClient = new HttpClient(mockHandler.Object);
var sut = new ClassUnderTest(httpClient);
//act
var actual = await sut.GetPersonAsync(personId);
//assert
Assert.NotNull(actual);
mockHandler.Protected().Verify(
"SendAsync",
Times.Exactly(1),
ItExpr.Is<HttpRequestMessage>(m => m.Method == HttpMethod.Get),
ItExpr.IsAny<CancellationToken>());
}
RichardSzalay.MockHttp (using BackendDefinition pattern)
[Fact]
public async Task RichardSzalayMockHttpUsingBackendDefinition()
{
//arrange
const int personId = 1;
using var mockHandler = new MockHttpMessageHandler();
var dto = new Person { Id = personId, Name = "Dave", Age = 42 };
var mockResponse = new HttpResponseMessage
{
StatusCode = HttpStatusCode.OK,
Content = JsonContent.Create<Person>(dto)
};
var mockedRequest = mockHandler.When(HttpMethod.Get, "https://myurl?id=1")
.Respond(mockResponse.StatusCode, mockResponse.Content);
// Inject the handler or client into your application code
var httpClient = mockHandler.ToHttpClient();
var sut = new ClassUnderTest(httpClient);
//act
var actual = await sut.GetPersonAsync(personId);
//assert
Assert.NotNull(actual);
Assert.Equivalent(dto, actual);
Assert.Equal(1, mockHandler.GetMatchCount(mockedRequest));
mockHandler.VerifyNoOutstandingRequest();
}
RichardSzalay.MockHttp (using RequestExpectation pattern)
[Fact]
public async Task RichardSzalayMockHttpUsingRequestExpectation()
{
//arrange
const int personId = 1;
using var mockHandler = new MockHttpMessageHandler();
var dto = new Person { Id = personId, Name = "Dave", Age = 42 };
var mockResponse = new HttpResponseMessage
{
StatusCode = HttpStatusCode.OK,
Content = JsonContent.Create<Person>(dto)
};
var mockedRequest = mockHandler.Expect(HttpMethod.Get, "https://myurl")
.WithExactQueryString($"id={personId}")
.Respond(mockResponse.StatusCode, mockResponse.Content);
// Inject the handler or client into your application code
var httpClient = mockHandler.ToHttpClient();
var sut = new ClassUnderTest(httpClient);
//act
var actual = await sut.GetPersonAsync(personId);
//assert
Assert.NotNull(actual);
Assert.Equivalent(dto, actual);
Assert.Equal(1, mockHandler.GetMatchCount(mockedRequest));
mockHandler.VerifyNoOutstandingExpectation();
}
Moq.Contrib.HttpClient
[Fact]
public async Task UsingMoqContribHttpClient()
{
//arrange
const int personId = 1;
var mockHandler = new Mock<HttpMessageHandler>(MockBehavior.Strict);
var dto = new Person { Id = personId, Name = "Dave", Age = 42 };
var mockUrl = $"https://myurl?id={personId}";
var mockResponse = mockHandler.SetupRequest(HttpMethod.Get, mockUrl)
.ReturnsJsonResponse<Person>(HttpStatusCode.OK, dto);
// Inject the handler or client into your application code
var httpClient = mockHandler.CreateClient();
var sut = new ClassUnderTest(httpClient);
//act
var actual = await sut.GetPersonAsync(personId);
//assert
Assert.NotNull(actual);
Assert.Equivalent(dto, actual);
mockHandler.VerifyRequest(HttpMethod.Get, mockUrl, Times.Once());
}
WireMock.NET
public class TestClass : IDisposable
{
private WireMockServer _server;
public TestClass()
{
_server = WireMockServer.Start();
}
public void Dispose()
{
_server.Stop();
}
[Fact]
public async Task UsingWireMock()
{
//arrange
const int personId = 1;
var dto = new Person { Id = personId, Name = "Dave", Age = 42 };
var mockUrl = $"https://myurl?id={personId}";
_server.Given(
Request.Create()
.WithPath("/"))
.RespondWith(
Response.Create()
.WithStatusCode(200)
.WithHeader("Content-Type", "application/json")
.WithBodyAsJson(dto));
// Inject the handler or client into your application code
var httpClient = _server.CreateClient();
var sut = new ClassUnderTest(httpClient);
//act
var actual = await sut.GetPersonAsync(personId);
//assert
Assert.NotNull(actual);
Assert.Equivalent(dto, actual);
}
}
If you don't mind running your own http server, you can try Xim. It's as easy as this:
using Xim.Simulators.Api;
[Test]
public async Task TestHttpGetMethod()
{
using var simulation = Simulation.Create();
using var api = simulation
.AddApi()
.AddHandler("GET /books/1234", ApiResponse.Ok())
.Build();
await api.StartAsync();
var httpClient = new HttpClient();
var response = await httpClient.SendAsync(new HttpRequestMessage(HttpMethod.Get, $"{api.Location}/books/1234"));
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
Assert.IsTrue(api.ReceivedApiCalls.Any(call => call.Action == "GET /books/1234"));
}
It's a nice alternative to using mocks and may suit your needs in some scenarios. It's built on top of Kestrel (and yes, I'm the author).
All you need is a test version of HttpMessageHandler class which you pass to HttpClient ctor. The main point is that your test HttpMessageHandler class will have a HttpRequestHandler delegate that the callers can set and simply handle the HttpRequest the way they want.
public class FakeHttpMessageHandler : HttpMessageHandler
{
public Func<HttpRequestMessage, CancellationToken, HttpResponseMessage> HttpRequestHandler { get; set; } =
(r, c) =>
new HttpResponseMessage
{
ReasonPhrase = r.RequestUri.AbsoluteUri,
StatusCode = HttpStatusCode.OK
};
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
return Task.FromResult(HttpRequestHandler(request, cancellationToken));
}
}
You can use an instance of this class to create a concrete HttpClient instance. Via the HttpRequestHandler delegate you have full control over outgoing http requests from HttpClient.
After carefully searching, I figured out the best approach to accomplish this.
private HttpResponseMessage response;
[SetUp]
public void Setup()
{
var handlerMock = new Mock<HttpMessageHandler>();
handlerMock
.Protected()
.Setup<Task<HttpResponseMessage>>(
"SendAsync",
ItExpr.IsAny<HttpRequestMessage>(),
ItExpr.IsAny<CancellationToken>())
// This line will let you to change the response in each test method
.ReturnsAsync(() => response);
_httpClient = new HttpClient(handlerMock.Object);
yourClinet = new YourClient( _httpClient);
}
As you noticed I have used Moq and Moq.Protected packages.
This is an old question, but I feel the urge to extend the answers with a solution I didn't see here.
You can fake the Microsoft assemly (System.Net.Http) and then use ShinsContext during the test.
In VS 2017, right click on the System.Net.Http assembly and choose "Add Fakes Assembly"
Put your code in the unit test method under a ShimsContext.Create() using. This way, you can isolate the code where you are planning to fake the HttpClient.
Depends on your implementation and test, I would suggest to implement all the desired acting where you call a method on the HttpClient and want to fake the returned value. Using ShimHttpClient.AllInstances will fake your implementation in all the instances created during your test. For example, if you want to fake the GetAsync() method, do the following:
[TestMethod]
public void FakeHttpClient()
{
using (ShimsContext.Create())
{
System.Net.Http.Fakes.ShimHttpClient.AllInstances.GetAsyncString = (c, requestUri) =>
{
//Return a service unavailable response
var httpResponseMessage = new HttpResponseMessage(HttpStatusCode.ServiceUnavailable);
var task = Task.FromResult(httpResponseMessage);
return task;
};
//your implementation will use the fake method(s) automatically
var client = new Connection(_httpClient);
client.doSomething();
}
}
Since HttpClient use SendAsync method to perform all HTTP Requests, you can override SendAsync method and mock the HttpClient.
For that wrap creating HttpClient to a interface, something like below
public interface IServiceHelper
{
HttpClient GetClient();
}
Then use above interface for dependency injection in your service, sample below
public class SampleService
{
private readonly IServiceHelper serviceHelper;
public SampleService(IServiceHelper serviceHelper)
{
this.serviceHelper = serviceHelper;
}
public async Task<HttpResponseMessage> Get(int dummyParam)
{
try
{
var dummyUrl = "http://www.dummyurl.com/api/controller/" + dummyParam;
var client = serviceHelper.GetClient();
HttpResponseMessage response = await client.GetAsync(dummyUrl);
return response;
}
catch (Exception)
{
// log.
throw;
}
}
}
Now in unit test project create a helper class for mocking SendAsync.
Here it is a FakeHttpResponseHandler class which is inheriting DelegatingHandler which will provide an option to override the SendAsync method. After overriding the SendAsync method need to setup a response for each HTTP Request which is calling SendAsync method, for that create a Dictionary with key as Uri and value as HttpResponseMessage so that whenever there is a HTTP Request and if the Uri matches SendAsync will return the configured HttpResponseMessage.
public class FakeHttpResponseHandler : DelegatingHandler
{
private readonly IDictionary<Uri, HttpResponseMessage> fakeServiceResponse;
private readonly JavaScriptSerializer javaScriptSerializer;
public FakeHttpResponseHandler()
{
fakeServiceResponse = new Dictionary<Uri, HttpResponseMessage>();
javaScriptSerializer = new JavaScriptSerializer();
}
/// <summary>
/// Used for adding fake httpResponseMessage for the httpClient operation.
/// </summary>
/// <typeparam name="TQueryStringParameter"> query string parameter </typeparam>
/// <param name="uri">Service end point URL.</param>
/// <param name="httpResponseMessage"> Response expected when the service called.</param>
public void AddFakeServiceResponse(Uri uri, HttpResponseMessage httpResponseMessage)
{
fakeServiceResponse.Remove(uri);
fakeServiceResponse.Add(uri, httpResponseMessage);
}
/// <summary>
/// Used for adding fake httpResponseMessage for the httpClient operation having query string parameter.
/// </summary>
/// <typeparam name="TQueryStringParameter"> query string parameter </typeparam>
/// <param name="uri">Service end point URL.</param>
/// <param name="httpResponseMessage"> Response expected when the service called.</param>
/// <param name="requestParameter">Query string parameter.</param>
public void AddFakeServiceResponse<TQueryStringParameter>(Uri uri, HttpResponseMessage httpResponseMessage, TQueryStringParameter requestParameter)
{
var serilizedQueryStringParameter = javaScriptSerializer.Serialize(requestParameter);
var actualUri = new Uri(string.Concat(uri, serilizedQueryStringParameter));
fakeServiceResponse.Remove(actualUri);
fakeServiceResponse.Add(actualUri, httpResponseMessage);
}
// all method in HttpClient call use SendAsync method internally so we are overriding that method here.
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
if(fakeServiceResponse.ContainsKey(request.RequestUri))
{
return Task.FromResult(fakeServiceResponse[request.RequestUri]);
}
return Task.FromResult(new HttpResponseMessage(HttpStatusCode.NotFound)
{
RequestMessage = request,
Content = new StringContent("Not matching fake found")
});
}
}
Create a new implementation for IServiceHelper by mocking framework or like below.
This FakeServiceHelper class we can use to inject the FakeHttpResponseHandler class so that whenever the HttpClient created by this class it will use FakeHttpResponseHandler class instead of the actual implementation.
public class FakeServiceHelper : IServiceHelper
{
private readonly DelegatingHandler delegatingHandler;
public FakeServiceHelper(DelegatingHandler delegatingHandler)
{
this.delegatingHandler = delegatingHandler;
}
public HttpClient GetClient()
{
return new HttpClient(delegatingHandler);
}
}
And in test configure FakeHttpResponseHandler class by adding the Uri and expected HttpResponseMessage.
The Uri should be the actual serviceendpoint Uri so that when the overridden SendAsync method is called from actual service implementation it will match the Uri in Dictionary and respond with the configured HttpResponseMessage.
After configuring inject the FakeHttpResponseHandler object to the fake IServiceHelper implementation.
Then inject the FakeServiceHelper class to the actual service which will make the actual service to use the override SendAsync method.
[TestClass]
public class SampleServiceTest
{
private FakeHttpResponseHandler fakeHttpResponseHandler;
[TestInitialize]
public void Initialize()
{
fakeHttpResponseHandler = new FakeHttpResponseHandler();
}
[TestMethod]
public async Task GetMethodShouldReturnFakeResponse()
{
Uri uri = new Uri("http://www.dummyurl.com/api/controller/");
const int dummyParam = 123456;
const string expectdBody = "Expected Response";
var expectedHttpResponseMessage = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new StringContent(expectdBody)
};
fakeHttpResponseHandler.AddFakeServiceResponse(uri, expectedHttpResponseMessage, dummyParam);
var fakeServiceHelper = new FakeServiceHelper(fakeHttpResponseHandler);
var sut = new SampleService(fakeServiceHelper);
var response = await sut.Get(dummyParam);
var responseBody = await response.Content.ReadAsStringAsync();
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
Assert.AreEqual(expectdBody, responseBody);
}
}
GitHub Link : which is having sample implementation
I did something very simple, as I was in a DI environment.
public class HttpHelper : IHttpHelper
{
private ILogHelper _logHelper;
public HttpHelper(ILogHelper logHelper)
{
_logHelper = logHelper;
}
public virtual async Task<HttpResponseMessage> GetAsync(string uri, Dictionary<string, string> headers = null)
{
HttpResponseMessage response;
using (var client = new HttpClient())
{
if (headers != null)
{
foreach (var h in headers)
{
client.DefaultRequestHeaders.Add(h.Key, h.Value);
}
}
response = await client.GetAsync(uri);
}
return response;
}
public async Task<T> GetAsync<T>(string uri, Dictionary<string, string> headers = null)
{
...
rawResponse = await GetAsync(uri, headers);
...
}
}
and the mock is:
[TestInitialize]
public void Initialize()
{
...
_httpHelper = new Mock<HttpHelper>(_logHelper.Object) { CallBase = true };
...
}
[TestMethod]
public async Task SuccessStatusCode_WithAuthHeader()
{
...
_httpHelper.Setup(m => m.GetAsync(_uri, myHeaders)).Returns(
Task<HttpResponseMessage>.Factory.StartNew(() =>
{
return new HttpResponseMessage(System.Net.HttpStatusCode.OK)
{
Content = new StringContent(JsonConvert.SerializeObject(_testData))
};
})
);
var result = await _httpHelper.Object.GetAsync<TestDTO>(...);
Assert.AreEqual(...);
}
Inspired by PointZeroTwo's answer, here's a sample using NUnit and FakeItEasy.
SystemUnderTest in this example is the class that you want to test - no sample content given for it but I assume you have that already!
[TestFixture]
public class HttpClientTests
{
private ISystemUnderTest _systemUnderTest;
private HttpMessageHandler _mockMessageHandler;
[SetUp]
public void Setup()
{
_mockMessageHandler = A.Fake<HttpMessageHandler>();
var httpClient = new HttpClient(_mockMessageHandler);
_systemUnderTest = new SystemUnderTest(httpClient);
}
[Test]
public void HttpError()
{
// Arrange
A.CallTo(_mockMessageHandler)
.Where(x => x.Method.Name == "SendAsync")
.WithReturnType<Task<HttpResponseMessage>>()
.Returns(Task.FromResult(new HttpResponseMessage
{
StatusCode = HttpStatusCode.InternalServerError,
Content = new StringContent("abcd")
}));
// Act
var result = _systemUnderTest.DoSomething();
// Assert
// Assert.AreEqual(...);
}
}
Perhaps there would be some code to change in your current project but for new projects you should absolutely consider using Flurl.
https://flurl.dev
It is a HTTP client library for .NET with a fluent interface that specifically enables testability for code that uses it to make HTTP requests.
There are plenty of code samples on the website but in a nutshell you use it like this in your code.
Add the usings.
using Flurl;
using Flurl.Http;
Send a get request and read the response.
public async Task SendGetRequest()
{
var response = await "https://example.com".GetAsync();
// ...
}
In the unit tests Flurl acts as a mock that can be configured to behave as desired and also to verify the calls that were done.
using (var httpTest = new HttpTest())
{
// Arrange
httpTest.RespondWith("OK", 200);
// Act
await sut.SendGetRequest();
// Assert
httpTest.ShouldHaveCalled("https://example.com")
.WithVerb(HttpMethod.Get);
}
To add my 2 cents. To mock specific http request methods either Get or Post. This worked for me.
mockHttpMessageHandler.Protected().Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.Is<HttpRequestMessage>(a => a.Method == HttpMethod.Get), ItExpr.IsAny<CancellationToken>())
.Returns(Task.FromResult(new HttpResponseMessage()
{
StatusCode = HttpStatusCode.OK,
Content = new StringContent(""),
})).Verifiable();

Unit Testing for async Task<ActionResult>

I am very new to ASP.NET CORE MVC and I was wondering if anyone could help me about my problem.
I was working in a project that will get all projects within a specific azure devops organization.
Here is my controller code:
public async Task<ActionResult> Organization(string selectedOrg, string oauth)
{
var client = new HttpClient();
IndexViewModel model = new IndexViewModel();
model.Organizations = OrganizationData.Data;
if (selectedOrg == null)
{
selectedOrg = model.Organizations.FirstOrDefault().OrgName;
}
else
{
model.SelectedOrg = selectedOrg;
}
var token = _cache.Get<TokenModel>("Token" + HttpContext.Session.GetString("TokenGuid"));
oauth = token.AccessToken;
var url = "https://dev.azure.com/" + selectedOrg + "/_apis/projects?api-version=4.1";
try
{
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", oauth);
var response = await client.GetAsync(url);
var responseBody = response.Content.ReadAsStringAsync().Result;
model.Projects = JsonConvert.DeserializeObject<ProjectsModel>(responseBody);
client.Dispose();
return View("Index", model);
}
catch(Exception e)
{
client.Dispose();
return Json(Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(e.ToString()));
}
}
Can anyone help how to do unit testing with this one? Or do I have to refactor this one?
You have way to many dependencies.
Why does the signature of the method pass an oauth value that is never used?
First off, calling any external dependency via http inside a controller should be frowned upon. This whole thing should be abstracted into it's own call. Since it appears to be getting data, this should actually be at your data tier. Covering a whole n-tier approach with separate projects is most likely out of scope, so lets just cover the bare minimum for unit testing in my opinion.
First you need to abstract your HttpClient. You can't really do unit test methods if they make any calls outside themselves (for the most part) because then it's not a unit test, it's an integration test.
// I don't have a full grasp of your complete eco-system so based on the
// minimal information provided, this would at least get you close
public interface IAzureAPI
{
public Task<string> GetOrgAsync(string org, string oauth);
}
public class AzureAPI : IDisposable
{
public async Task<string> GetOrgAsync(string org, string oauth)
{
// use *using* not try/catch/finally/dispose
using (var client = new HttpClient())
{
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", oauth);
var url = "https://dev.azure.com/" + org+ "/_apis/projects?api-version=4.1";
var response = await client.GetAsync(url);
// never use `.Result` unless you absolutely know what you are doing
// always using async/wait if possible
var result = await response.Content.ReadAsStringAsync();
return result;
}
}
}
Hopefully you are using a DI Framework:
public class MyController
{
private IAzureAPI _azureAPI;
public MyController(IAzureAPI azureAPI)
{
_azureAPI = azureAPI;
}
}
Now onto the hard part:
public async Task<ActionResult> Organization(string selectedOrg, string oauth)
{
IndexViewModel model = new IndexViewModel();
// I have no idea where model came from so
// this appears to block "unit-testing"
// strange that you don't validate `selectedOrg`, you just use it
model.Organizations = OrganizationData.Data;
if (selectedOrg == null)
{
selectedOrg = model.Organizations.FirstOrDefault().OrgName;
}
else
{
model.SelectedOrg = selectedOrg;
}
// no idea where `_cache` came from so
// also appears to block "unit-testing"
// As does `HttpContext` because you aren't using the
// Interface
var token = _cache.Get<TokenModel>("Token" + HttpContext.Session.GetString("TokenGuid"));
oauth = token.AccessToken;
try
{
var orgInfo = await _azureAPI.GetOrgAsync(selectedOrg, oauth);
model.Projects = JsonConvert.DeserializeObject<ProjectsModel>(orgInfo);
// return a view here???
return View("Index", model);
}
catch(Exception e)
{
// return JSON here instead????
return Json(Newtonsoft.Json.JsonConvert.DeserializeObject<dynamic>(e.ToString()));
}
}
That's a general start, but there are too many unknowns, and to many dependencies to actually write a real unit test. Here is a quick structure and semi-test based on the information you've provided.
public MyControllerTests
{
// for 100% Cover Coverage you'd need all of these
public async Task Organization_OrgAsString_ReturnsView
{
//...
}
public async Task Organization_OrgAsNull_ReturnsView
{
// Arrange
var azureAPI = Substitute.For<IAzureAPI>();
azureAPI.GetOrgAsync(null, null)
.Returns("somestring");
var controller = new MyController(azureAPI);
// Act
var result = await controller.Organization(null, null);
// Assert
Assert.That(result....);
}
public async Task Organization_WithException_ReturnsJson
{
//...
}
}

Can a static helper class be used for WebApi calls (from UI)?

I have X controllers that use a API site (WebApi). I have created an ApiHelper class. Which I use in these controllers. Now my question is this. Can I make this ApiHelper a static class? I think I can because the httpClient is instanced. Or do I overlook something, and does it need to be an instanced ApiHelper. (the use of static still confuses me sometimes). Example code below.
public class HomeController : Controller
{
public async Task<string> VersionDemo()
{
var response = await ApiHelper.Call("/api/config/version");
var data = response.Content.ReadAsStringAsync();
var res = Newtonsoft.Json.JsonConvert.DeserializeObject<string>(data.Result);
return res;
}
}
public class ConfigController : Controller
{
private async Task<List<ConfigSetting>> GetGeneralConfigurationDemo()
{
var generalConfiguration = new List<ConfigSetting>();
var response = await ApiHelper.Call("api/configuration/GetGeneralConfiguration");
var data = response.Content.ReadAsStringAsync();
generalConfiguration = JsonConvert.DeserializeObject<List<ConfigSetting>>(data.Result);
return generalConfiguration;
}
}
public static class ApiHelper
{
public static async Task<HttpResponseMessage> Call(string url)
{
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;
var baseAdress = System.Configuration.ConfigurationManager.AppSettings["ApiBaseAddress"];
string apiUrl = baseAdress + url;
using (HttpClient client = new HttpClient())
{
client.BaseAddress = new Uri(apiUrl);
client.DefaultRequestHeaders.Accept.Clear();
client.DefaultRequestHeaders.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage response = await client.GetAsync(apiUrl);
return response;
}
}
}
Make base controller and hide http client as protected thing.
public abstract class BaseController : Controller
{
protected ApiHelper Api { get; set; }
}
Then derive your controllers from BaseController
public class ConfigController : BaseController {}
public class HomeController : BaseController {}
Note : try not to use static classes cause they make your heap littered. They are allocated in "high-frequency" heap, which is never garbage collected.
There would be no problem to leave your class static as the HttpClient stays on the method scope and thus each call to your static method will use a different HttpClient. It would not be safe if you used a static member (field or property) as it would be shared by all the callers and you would need to synchronize the access (for a multi thread usage).
After reading (httpClient your are doing it wrong , singleton pattern) and subsequently testing. I ended up using the following code. Main goal is one httpClient application wide and avoid socket exhaustion.
In my controllers where I'm in need of a httpClient I use the HttpClientSingleton.Instance see below.
And here is a BaseController you can inherit from in your controllers that are going to use your API.
public class BaseController : Controller
{
public readonly string ApiBaseAdress = System.Configuration.ConfigurationManager.AppSettings["ApiBaseAddress"];
public BaseController()
{
//Set as needed Servicepoint settings
//string SecurityProtocolTypeFromConfig = System.Configuration.ConfigurationManager.AppSettings["SecurityProtocolType"];
//SecurityProtocolType fromConfig;
//Enum.TryParse(SecurityProtocolTypeFromConfig, out fromConfig);
//ServicePointManager.SecurityProtocol = fromConfig;
//possible ServicePoint setting needed in some cases.
//ServicePointManager.Expect100Continue = false;
//ServicePointManager.MaxServicePointIdleTime = 2000;
//ServicePointManager.SetTcpKeepAlive(false, 1, 1);
}
}
And here is the HttpClientSingleton class:
public sealed class HttpClientSingleton
{
private static readonly Lazy<HttpClient> lazy = new Lazy<HttpClient>(() => new HttpClient());
public static HttpClient Instance { get { return lazy.Value; } }
private HttpClientSingleton()
{
}
}
So putting it together. Here is an example of getting some loginfo from the API.
public class MyLogController : BaseController
{
[HttpPost]
public async Task<JsonResult> log(string requestId)
{
var url = ApiBaseAdress + string.Format("/api/runs/log/{0}", requestId);
List<Log> logs = new List<Log>();
var response = await HttpClientSingleton.Instance.GetAsync(url);
response.EnsureSuccessStatusCode();
var result = await response.Content.ReadAsStringAsync();
logs = JsonConvert.DeserializeObject<List<Log>>(result);
return Json(logs);
}
}
You can write a static helper class. If the name is ApiHelper, then add a Microsoft.AspNet.WebApi.Client reference. When your app is initialized, call the class's InitializeClient() method, and you can call the GetAsync() method if you need. The code is below:
public static class ApiHelper
{
public static HttpClient ApiClient { get; set; }
public static void InitializeClient()
{
ApiClient = new HttpClient();
ApiClient.DefaultRequestHeaders.Accept.Clear();
ApiClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
}
public static async Task<T> GetAsync<T>(string url)
{
using (HttpResponseMessage response = await ApiHelper.ApiClient.GetAsync(url))
{
if (response.IsSuccessStatusCode)
{
var result = await response.Content.ReadAsAsync<T>();
return result;
}
else
{
throw new Exception(response.ReasonPhrase);
}
}
}
}

Challenge in calling dependency service from Xamarin

I'm working on accessing REST Api from Xamarin forms. I have created an interface in portable class like this by adding
public interface IRestService<T>
{
void Post(T item, string resourceURL);
}
public interface IRepository
{
}
and in Drod Project I'm implemented the interface like this.
[assembly:Xamarin.Forms.Dependency(typeof(RestOperationsDroid))]
namespace VLog.Droid.DependencyServices
{
public class RestOperationsDroid : IRestService<IRepository>
{
private const string BaseURL = "http://127.0.0.1/logger/v1/";
HttpClient client;
public RestOperationsDroid()
{
client = new HttpClient();
client.MaxResponseContentBufferSize = 256000;
}
public async void Post(object item, string url)
{
var uri = new Uri(string.Format(BaseURL + url));
var jsoncontent = new StringContent(JsonConvert.SerializeObject(item), Encoding.UTF8, "application/json");
HttpResponseMessage response = null;
response = await client.PostAsync(uri, jsoncontent);
if (response.IsSuccessStatusCode)
{
//Debug(#" TodoItem successfully saved.");
}
else
{
//throw new Exception("Failed to Post data");
}
}
}
}
Calling in Xamarin.Forms (PCL project)
DependencyService.Get<IRestService<Log>>().Post(_logitem, "sync");
I'm getting an error says :
Object reference not set to an instance of an object.
What went wrong in this implementation ?
You are trying to resolve an IRestService<Log> from the DependencyService, while your class implements IRestService<IRepository>. These are different types. You should implement a class that implements the specific type you want for IRestService<T>.

How can I use FakeItEasy with HttpClient, in a unit test?

I'm trying to figure out how to use FakeItEasy with the HttpClient, given the following code:
public Foo(string key, HttpClient httpClient = null)
{ .. }
public void DoGet()
{
....
if (_httpClient == null)
{
_httpClient = new HttpClient();
}
var response = _httpClient.GetAsync("user/1);
}
public void DoPost(foo Foo)
{
if (_httpClient == null)
{
_httpClient = new HttpClient();
}
var formData = new Dictionary<string, string>
{
{"Name", "Joe smith"},
{"Age", "40"}
};
var response = _httpClient.PostAsync("user",
new FormUrlEncodedContent(formData));
}
So i'm not sure how to use FakeItEasy, to fake out the HttpClient's GetAsync and PostAsync methods.
production code will not pass in the HttpClient, but the unit test will pass in the fake instance, made by FakeItEasy.
eg.
[Fact]
public void GivenBlah_DoGet_DoesSomething()
{
// Arrange.
var httpClient A.Fake<HttpClient>(); // <-- need help here.
var foo = new Foo("aa", httpClient);
// Act.
foo.DoGet();
// Assert....
}
UPDATE:
I grok that FiE (and most mocking packages) works on interfaces or virtual methods. So for this question, lets just prentend that the GetAsync and PostAsync methods are virtual ... please :)
Here's my (more or less) general purpose FakeHttpMessageHandler.
public class FakeHttpMessageHandler : HttpMessageHandler
{
private HttpResponseMessage _response;
public static HttpMessageHandler GetHttpMessageHandler( string content, HttpStatusCode httpStatusCode )
{
var memStream = new MemoryStream();
var sw = new StreamWriter( memStream );
sw.Write( content );
sw.Flush();
memStream.Position = 0;
var httpContent = new StreamContent( memStream );
var response = new HttpResponseMessage()
{
StatusCode = httpStatusCode,
Content = httpContent
};
var messageHandler = new FakeHttpMessageHandler( response );
return messageHandler;
}
public FakeHttpMessageHandler( HttpResponseMessage response )
{
_response = response;
}
protected override Task<HttpResponseMessage> SendAsync( HttpRequestMessage request, CancellationToken cancellationToken )
{
var tcs = new TaskCompletionSource<HttpResponseMessage>();
tcs.SetResult( _response );
return tcs.Task;
}
}
Here is an example of it being used from one of my tests that expects some JSON as a return value.
const string json = "{\"success\": true}";
var messageHandler = FakeHttpMessageHandler.GetHttpMessageHandler(
json, HttpStatusCode.BadRequest );
var httpClient = new HttpClient( messageHandler );
You would now inject httpClient into your class under test (using whatever injection mechanism you prefer) and when GetAsync is called your messageHandler will spit back the result you told it to.
You could also create an AbstractHandler on which you can intercept a public abstract method. For instance:
public abstract class AbstractHandler : HttpClientHandler
{
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
return Task.FromResult(SendAsync(request.Method, request.RequestUri.AbsoluteUri));
}
public abstract HttpResponseMessage SendAsync(HttpMethod method, string url);
}
Then you can intercept calls to the AbstractHandler.SendAsync(HttpMethod method, string url) like:
// Arrange
var httpMessageHandler = A.Fake<AbstractHandler>(options => options.CallsBaseMethods());
A.CallTo(() => httpMessageHandler.SendAsync(A<HttpMethod>._, A<string>._)).Returns(new HttpResponseMessage(HttpStatusCode.OK) { Content = new StringContent("Result")});
var httpClient = new HttpClient(httpMessageHandler);
// Act
var result = await httpClient.GetAsync("https://google.com/");
// Assert
Assert.Equal("Result", await result.Content.ReadAsStringAsync());
A.CallTo(() => httpMessageHandler.SendAsync(A<HttpMethod>._, "https://google.com/")).MustHaveHappenedOnceExactly();
More information can be found on this blog: https://www.meziantou.net/mocking-an-httpclient-using-an-httpclienthandler.htm
I did something like this when I needed to interact with the Gravatar service. I tried to use fakes/mocks but found it was impossible with HttpClient. Instead, I came up with a custom HttpMessageHandler class that lets me pre-load the expected response, along these lines:
using System.Net.Http;
using System.Threading;
using System.Threading.Tasks;
namespace Tigra.Gravatar.LogFetcher.Specifications
{
/// <summary>
/// Class LoggingHttpMessageHandler.
/// Provides a fake HttpMessageHandler that can be injected into HttpClient.
/// The class requires a ready-made response message to be passed in the constructor,
/// which is simply returned when requested. Additionally, the web request is logged in the
/// RequestMessage property for later examination.
/// </summary>
public class LoggingHttpMessageHandler : DelegatingHandler
{
internal HttpResponseMessage ResponseMessage { get; private set; }
internal HttpRequestMessage RequestMessage { get; private set; }
public LoggingHttpMessageHandler(HttpResponseMessage responseMessage)
{
ResponseMessage = responseMessage;
}
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
CancellationToken cancellationToken)
{
RequestMessage = request;
return Task.FromResult(ResponseMessage);
}
}
}
Then my test context setup goes something like this:
public class with_fake_gravatar_web_service
{
Establish context = () =>
{
MessageHandler = new LoggingHttpMessageHandler(new HttpResponseMessage(HttpStatusCode.OK));
GravatarClient = new HttpClient(MessageHandler);
Filesystem = A.Fake<FakeFileSystemWrapper>();
Fetcher = new GravatarFetcher(Committers, GravatarClient, Filesystem);
};
protected static LoggingHttpMessageHandler MessageHandler;
protected static HttpClient GravatarClient;
protected static FakeFileSystemWrapper Filesystem;
}
Then, here's an example of a test (specification) that uses it:
[Subject(typeof(GravatarFetcher), "Web service")]
public class when_fetching_imagaes_from_gravatar_web_service : with_fake_gravatar_web_service
{
Because of = () =>
{
var result = Fetcher.FetchGravatars(#"c:\"); // This makes the web request
Task.WaitAll(result.ToArray());
//"http://www.gravatar.com/avatar/".md5_hex(lc $email)."?d=404&size=".$size;
UriPath = MessageHandler.RequestMessage.RequestUri.GetComponents(UriComponents.Path, UriFormat.Unescaped);
};
It should_make_request_from_gravatar_dot_com =
() => MessageHandler.RequestMessage.RequestUri.Host.ShouldEqual("www.gravatar.com");
It should_make_a_get_request = () => MessageHandler.RequestMessage.Method.ShouldEqual(HttpMethod.Get);
// see https://en.gravatar.com/site/check/tim#tigranetworks.co.uk
It should_request_the_gravatar_hash_for_tim_long =
() => UriPath.ShouldStartWith("avatar/df0478426c0e47cc5e557d5391e5255d");
static string UriPath;
}
You can see the full source at http://stash.teamserver.tigranetworks.co.uk/users/timlong/repos/tigra.gravatar.logfetcher/browse
FakeItEasy, like most mocking libraries, does not create proxies for non-abstract components. In the case of HttpClient, the GetAsync and PostAsync methods are neither virtual nor abstract, so you can't create stub implementations of them directly. See https://github.com/FakeItEasy/FakeItEasy/wiki/What-can-be-faked.
In this case, you need a different abstraction as a dependency - one which HttpClient can fulfill, but so could other implementations, including mocks/stubs.
This isn't answering your question directly, but I wrote a library a while back that provides an API for stubbing out requests/responses. It's pretty flexible, and supports ordered/unordered matching as well as a customisable fallback system for unmatched requests.
It's available on GitHub here: https://github.com/richardszalay/mockhttp

Categories