David Tembo
David Tembo

Reputation: 89

Mocked HttpClientFactory returns null when creating client

I am trying to unit test a service that uses the IHttpClientFactory with Nunit and NSubstitute for mocking.

The service I want to test looks like this

public class Movies : IMovies
{
    private readonly IHttpClientFactory _httpClientFactory;

    public Movies(IHttpClientFactory httpClientFactory)
    { 
        _httpClientFactory = httpClientFactory;
    }

    public async Task<MovieCollection> GetPopularMovies(int PageNumber = 1)
    {

        // Get an instance of HttpClient from the factpry that we registered
        // in Startup.cs
         var client = _httpClientFactory.CreateClient("Movie Api");

        // Call the API & wait for response. 
        // If the API call fails, call it again according to the re-try policy
        // specified in Startup.cs
        var result =
            await client.GetAsync($"movie/popular?api_key=<the_api_key>language=en-US&page={PageNumber}");
        if (result.IsSuccessStatusCode)
        {
            // Read all of the response and deserialise it into an instace of

            var content = await result.Content.ReadAsStringAsync();
            return JsonConvert.DeserializeObject<MovieCollection>(content);
        }

        return null;
    }
}

When I run the test I get an error that says

System.NullReferenceException : Object reference not set to an instance of an object. at MovieApi.Services.Movies.GetPopularMovies(Int...

Here is the test I am running.The error occurs only when I put the keyword await in the line

var result = await service.GetPopularMovies(1);

Check the Test code below:

[Test]
public async Task GetPopular_WhenCalled_ReturnOK()
{

  //arrange
  var moviecollection = new MovieCollection();
  var httpClientFactoryMock = Substitute.For<IHttpClientFactory>();

  var fakeHttpMessageHandler = new FakeHttpMessageHandler(new HttpResponseMessage() {
    StatusCode = HttpStatusCode.OK,
    Content = new StringContent(JsonConvert.SerializeObject(moviecollection), Encoding.UTF8, "application/json") 
  });
  var fakeHttpClient = new HttpClient(fakeHttpMessageHandler);

  httpClientFactoryMock.CreateClient().Returns(fakeHttpClient);

  // Act
  var service = new Movies(httpClientFactoryMock);
  var result = await service.GetPopularMovies(1);
  //assert
  Assert.IsNotNull(result);
}

Upvotes: 0

Views: 3669

Answers (1)

Nkosi
Nkosi

Reputation: 246998

The subject method under test calls

 var client = _httpClientFactory.CreateClient("Movie Api");

but you configure the mock to return when CreateClient() is invoked.

httpClientFactoryMock.CreateClient().Returns(fakeHttpClient);

which means that when testing and CreateClient("Movie Api") is invoked the mock wont know what to do and thus returns null, causing the next call to throw NRE

Setup the mock to behave as expected when the system under test is invoked.

//...

httpClientFactoryMock.CreateClient("Movie Api").Returns(fakeHttpClient);

//...

Upvotes: 4

Related Questions