0

I have a service-class that gets a FlurlHttpClient injected in the constructor.

It has a public method which makes a call using the httpClient and then parses the response and returns a class. So basically I want to fake the response from the API and test the parse-method, which is private.

How do I unit test this? I am using NUnit and FakeItEasy for testing. So far I got this, but how do I ensure that the ParseResult-method gets tested with the faked result from the API?

Code so far:

Unit-test:

[Test]
public void GetShipmentData_SuccessfullTracking_ReturnsValidEntity() {
  //Fake the service-class
  var sut = A.Fake<IApiClient>();
  using (var httpTest = new HttpTest()) {
    httpTest.RespondWithJson(GetJsonFromFile("../../../Assets/SuccessfullApiTrackingResponse.json"), 200);

    //This does not actually run the function on the service-class.
    var response = sut.TrackShipmentUsingReferenceNumber("fakeReferenceNumber");

    Assert.IsTrue(response.SuccessfullShipmentTracking);
    Assert.IsNotNull(response.ApiResponseActivity);
  }
}

Api-class:

public class ApiClient : IApiClient {

    readonly ILogger _logger;
    private readonly IFlurlClient _httpClient;

    public ApiClient(IFlurlClientFactory flurlClientFac) {
      _httpClient = flurlClientFac.Get(ApiClientConfiguration.BaseAdress);
    }

    public ApiResponse TrackShipmentUsingReferenceNumber(string referenceNumber) {
      var request = GenerateApiRequestUsingReferenceNumber(referenceNumber);
      var response = _httpClient.Request("Track").PostJsonAsync(request).ReceiveString();

      return ParseResult(response.Result);
    }

    private ApiResponse ParseResult(string input) {
        //Shortened
      return = JObject.Parse<ApiResponse>(input);
    }
}
dymanoid
  • 14,771
  • 4
  • 36
  • 64
  • 1
    You don't want to fake IApiClient but IFlurlClientFactory. For this, create the IFlurlClientFactory and instantiate ApiClient with it. Now you can test it. – Philippe Sep 06 '19 at 13:46

1 Answers1

1

@Philippe already provided a good answer ( even if it's just a comment ... ), this is meant to be an alternative.

This is one of those cases where I would not want to mock anything. What you want to test is the private method which takes as input a string.

Imagine how easy it was if :

A. the method was public instead, all you'd have to do is literally call it with whatever input you wanted. Easy, no mocking.

B. Assuming it does way more than just what you shared, you could take it out of this class entirely into its own class which only deals with parsing a result and again, it would be trivial to test without mocking.

This would be a functional way of coding and it makes testing so much easier.

Andrei Dragotoniu
  • 6,155
  • 3
  • 18
  • 32
  • Thank you for your reply! I will break out my method to a helper class and do the isolated tests there. Its hard to know the tipping point to where you should break stuff out, but in this case it seems best. –  Sep 06 '19 at 14:51