How to unit test a class that consumes an HttpClient with IHttpClientFactory in ASP.NET Core?

Introduction

A few years ago, Microsoft introduced the HttpClient class as a modern substitute for HttpWebRequest to make web requests from .NET applications. Not only is this new API much easier to use, cleaner, and asynchronous, but it is also easily expandable.

The HttpClient class has a constructor that accepts a HttpMessageHandler.
The latter is an object that accepts a request (HttpRequestMessage) and returns a response (HttpResponseMessage); the way it does it is completely dependent on the implementation. By default, HttpClient uses HttpClientHandler, a handler that sends a request to a server on the network and returns the response from the server. In this article we will create our own implementation of an HttpMessageHandler by inheriting an abstract class named DelegatingHandler.

Finally, for all this to be possible,  HttpClient must not be used directly, but used with the dependency injection that allow mocking by using IHttpClientFactory interface.

Let’s create a fake HttpMessageHandler

For this example we will talk only about HttpResponseMessage, I won’t treat HttpRequestMessage.

All along this article I will demonstrate how to unit test a class by “mocking” the Http Response.

Here is a sample of a fake  HttpMessageHandler:

public class FakeHttpMessageHandler : DelegatingHandler
{
   private HttpResponseMessage _fakeResponse;

   public FakeHttpMessageHandler(HttpResponseMessage responseMessage)
   {
      _fakeResponse = responseMessage;
   }

   protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
   {
      return await Task.FromResult(_fakeResponse);
   }
}

I just override SendAsync and code my own implementation method because I inherit from an abstract class named DelegatingHandler as we talked in introduction.

Once done we just need to add a constructor that accept in parameter a HttpResponseMessage. That’s it ! 🙂

Let’s write a service that uses IHttpClientFactory interface

We will build a service that requests a list of user over a http call to a remote resource:

public class UserService
{
   private readonly IHttpClientFactory _httpFactory;

   public UserService(IHttpClientFactory httpFactory)
   {
      _httpFactory = httpFactory;
   }

   public async Task<List<User>> GetUsers(string url)
   {
       using (HttpClient httpclient = _httpFactory.CreateClient())
       using (HttpResponseMessage response = await httpclient.GetAsync(url))
       {
          if (response.StatusCode == HttpStatusCode.OK)
          {
             List<User> users = await response.Content.ReadAsAsync<List<User>>();
             return users;
          }
          return null; 
       }
    }
}

User contract:

public class User
{
   public string FirstName { get; set; }
   public string LastName { get; set; }
}

As you can see, using IHttpClientFactory allows us to mock the HttpClient instanciation

Let’s test this!

In these unit tests we will use XUnitFluentAssertion and NSubstitute

Scenario 1: let’s mock a call that return two users

public class UserServiceTests
{
   [Fact]
    public async Task WhenACorrectUrlIsProvided_ServiceShouldReturnAlistOfUsers()
    {
       // Arrange
       var users = new List<User>
       {
          new User
          {
             FirstName = "John",
             LastName = "Doe"
          },
          new User
          {
             FirstName = "John",
             LastName = "Deere"
          }
       };

       var httpClientFactoryMock = Substitute.For<IHttpClientFactory>();
       var url = "http://good.uri";
       var fakeHttpMessageHandler = new FakeHttpMessageHandler(new HttpResponseMessage() {
          StatusCode = HttpStatusCode.OK,
          Content = new StringContent(JsonConvert.SerializeObject(users), Encoding.UTF8, "application/json") 
       });
       var fakeHttpClient = new HttpClient(fakeHttpMessageHandler);

       httpClientFactoryMock.CreateClient().Returns(fakeHttpClient);

       // Act
       var service = new UserService(httpClientFactoryMock);
       var result = await service.GetUsers(url);

      // Assert
      result
      .Should()
      .BeOfType<List<User>>()
      .And
      .HaveCount(2)
      .And
      .Contain(x => x.FirstName == "John")
      .And
      .Contain(x => x.LastName == "Deere")
      .And
      .Contain(x => x.LastName == "Doe");
    }
}

As you can see, we expect an HttpStatusCode to “OK” and two users (set in the content).

We expect data in JSON format in the service : List<User> users = await response.Content.ReadAsAsync<List<User>>();

That’s why we need to set the encoding and the media type, else, by default it’s considered as text/plain: new StringContent(JsonConvert.SerializeObject(users), Encoding.UTF8, “application/json”)

We instantiate the HttpClient with the fake handler and then we define our expectation for the mock : httpClientFactoryMock.CreateClient().Returns(fakeHttpClient);

To finish we just need to make our assertions and we are done 🙂

Scenario 2: let’s mock a call that uses a bad Url an return Http 404 and null data

public class UserServiceTests
{
   [Fact]
    public async Task WhenABadUrlIsProvided_ServiceShouldReturnNull()
    {
       // Arrange
       var httpClientFactoryMock = Substitute.For<IHttpClientFactory>();
       var url = "http://bad.uri";
       var fakeHttpMessageHandler = new FakeHttpMessageHandler(new HttpResponseMessage() {
          StatusCode = HttpStatusCode.NotFound
       });
       var fakeHttpClient = new HttpClient(fakeHttpMessageHandler);

       httpClientFactoryMock.CreateClient().Returns(fakeHttpClient);

       // Act
       var service = new UserService(httpClientFactoryMock);
       var result = await service.GetUsers(url);

      // Assert
      result
      .Should()
      .BeNullOrEmpty();
    }
}

Like the service is implemented, if there is an http not found, the result set is null, simply! 😉

You are now able to unit test your classes that make http calls wuth HttpClient easily.

Hope this article helped you 🙂

How to fix unit test discovery in VS 2017 with MSTest V2?

Introduction

Microsoft Test Framework “MSTest V2” is the evolution of the Microsoft Test Framework and Adapter.

I wanted to try this new framework test by creating a new test project from an empty class library instead of using a MsTest test project and I got in trouble…..

My unit tests were not discovered by Visual Studio 2017.

How did I fix this?

What I have installed

I have installed the following packages:

Then I checked if my unit tests were displayed on Test Explorer and they were not 🙁 , I even tried to run them but I got this message:

What I did to find the issue

There are many reason that can explain this issue, so to know what’s going on I ran the following command line in the unit test project directory:

> dotnet test

It’s the same command that Visual Studio executes but by this way, you will see the precise error if there is an error during execution of the command line:

In my case I knew easily what I missed since the beginning!

I missed the installation of Microsoft.NET.Tests.Sdk package!

I just installed it and I was able to run my tests 🙂

Hope it has helped you 🙂

How to unit test private methods in .NET Core applications? (even if it’s bad)

Introduction

Yes it’s bad and dirty!

Since your private methods are only an implementation detail whose existence and behavior is only justified by their use in public methods, then these private methods are automatically tested through public method tests.

In other words, once your public methods are tested, your private methods should be fully covered. If this is not the case, it is either that you have forgotten tests or that your private method does things that are of no use to meet the needs of your public methods. In this case, it is probably necessary to clean them.

“Yes, but my private methods are big and complicated, tests would be very practical Sometimes, we see private methods that are full of stuff or things so complicated, that having tests would still be very practical.”

That is true. We see some.

Even myself I have been I was confronted with this kind of problem:

“Sometimes a bug is located in a private method and I do not want to recreate all the context necessary to call the public method.”

That’s why I’m going to show you how to test them, but do not forget that this should be truly exceptional.

How to?

This is really more simple than you think! we will just use Reflection.

In this example, I will use XUnit and FluentAssertion.

Let’s define a class with a private method:

namespace XUnitAndFluentAssertionDemo
{
   public class Hello
   {
      private string _firstName { get; set; }
      private string _lastName { get; set; }

      public Hello(string firstName, string lastName)
      {
         _firstName = firstName;
         _lastName = lastName;
      }

      public string HelloMan()
      {
        if (string.IsNullOrEmpty(_firstName))
        throw new MissingFirstNameException();

        return this.HelloMan(_firstName, _lastName);
      }

      private string HelloMan(string firstName, string lastName)
      {
         return $"Hello {firstName} {lastName} !";
      }

   }

   public class MissingFirstNameException: Exception
   {
      public MissingFirstNameException(): base("FirstName is missing")
      {
      }
   }
}

Now let’s write the unit test using Reflection:

We will use the well known function Activator.CreateInstance and fetch its methods and properties using Linq, then invoke the method to test with the well known method Invoke:

namespace UnitTests
{
   public class HelloTests
   {
      [Fact]
       public void PrivateHelloManShouldBeWellFormated()
       {
          // Arrange
          var firstName = "John";
          var lastName = "Doe";

          Type type = typeof(Hello);
          var hello = Activator.CreateInstance(type, firstName, lastName);
          MethodInfo method = type.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance)
          .Where(x => x.Name == "HelloMan" && x.IsPrivate)
          .First();

          //Act
          var helloMan = (string)method.Invoke(hello, new object [] {firstName, lastName});

         //Assert
         helloMan
         .Should()
         .StartWith("Hello")
         .And
         .EndWith("!")
         .And
         .Contain("John")
         .And
         .Contain("Doe");
       }
    }
}

Conclusion

Wondering “how to test a private method” should raise an alarm.

You should first find a solution to avoid this, review your code, but often it’s not easy because you maintain very old legacy code or your colleagues are stubborn :).

Anyway, I hope this article would help you.

Good luck 🙂