2

I'm trying to unit test a controller that is catching a FlurlHttpException and calling GetResponseJson<TError>() to get the error message in the catch block. I attempted to mock the exception, but the Call property does not allow me set the Settings. When the unit test runs it fails because there isn't a JsonSerializer in the settings. How do I setup this test?

Here's my current attempt that does not work:

Controller

[Route]
public async Task<IHttpActionResult> Post(SomeModel model)
{
    try
    {
        var id = await _serviceClient.Create(model);

        return Ok(new { id });
    }
    catch (FlurlHttpException ex)
    {
        if (ex.Call.HttpStatus == HttpStatusCode.BadRequest)
           return BadRequest(ex.GetResponseJson<BadRequestError>().Message);
        throw;
    }
}

Unit Test

[TestMethod]
public async Task Post_ServiceClientBadRequest_ShouldReturnBadRequestWithMessage()
{
    //Arrange
    string errorMessage = "A bad request";
    string jsonErrorResponse = JsonConvert.SerializeObject(new BadRequestError { Message = errorMessage });
    var badRequestCall = new HttpCall
    {
        Response = new HttpResponseMessage(HttpStatusCode.BadRequest),
        ErrorResponseBody = jsonErrorResponse
        //This would work, but Settings has a private set, so I can't
        //,Settings = new FlurlHttpSettings { JsonSerializer = new NewtonsoftJsonSerializer(new JsonSerializerSettings()) }
    };

    _mockServiceClient
        .Setup(client => client.create(It.IsAny<SomeModel>()))
        .ThrowsAsync(new FlurlHttpException(badRequestCall, "exception", new Exception()));

    //Act
    var result = await _controller.Post(new SomeModel());
    var response = result as BadRequestErrorMessageResult;

    //Assert
    Assert.IsNotNull(response);
    Assert.AreEqual(errorMessage, response.Message);
}
DerekMT12
  • 1,329
  • 11
  • 15
  • I'm thinking `.ReturnsAsync(() => thow new FlurlHttpException(badRequestCall, "exception", new Exception()))` – Nkosi Sep 20 '16 at 16:10
  • `ThrowsAsync` works correctly. It's just creating that `FlurlHttpException` by hand does not allow me to populate the `Settings` property, which causes the error. – DerekMT12 Sep 20 '16 at 16:12
  • Oh ok I misunderstood. will continue looking – Nkosi Sep 20 '16 at 16:13
  • The internal setter is called in this class https://github.com/tmenier/Flurl/blob/840a690f13b66e4b30ecc02d2560481287ba5908/src/Flurl.Http.Shared/FlurlClient.cs may be you could start there – Nkosi Sep 20 '16 at 16:23
  • Taking that into consideration, I would not be able to truly unit test just my controller. I'd have to create a concrete instance of my service client (used in the controller) and mock the Flurl call. That would work, but it's not ideal. – DerekMT12 Sep 20 '16 at 16:35
  • I concur with your assessment. That's the problem with static. It makes unit testing difficult. What is the throwing of an exception so tightly coupled. – Nkosi Sep 20 '16 at 16:36

1 Answers1

2

If you are encapsulating the usage of Flurl within your ServiceClient object, then I think catching FlurlException, extracting Message, and returning a more appropriate exception should also be encapsulated in that service. This will make your controller much easier to test.

Todd Menier
  • 37,557
  • 17
  • 150
  • 173