3

I am trying to test my API by calling an endpoint which should return an error message (json response). When testing this in Postman, the API indeed returns correct JSON and I am able to see that the status code is not 200. However, when trying to test this while using xunit and HttpClient, I am getting the following error message:

System.Net.Http.HttpRequestException : Error while copying content to a stream.

I am trying to figure out why this is happening. In my API I am checking credentials and if they are not correct, I will throw an Exception. This exception will get caught by a global exception handler, which will set the correct status code and create a json response.

Exception handler:

public class ExceptionHandler : IExceptionFilter
{
    public void OnException(ExceptionContext context)
    {
        int status = (int)HttpStatusCode.InternalServerError;
        String message = context.Exception.Message;
        var exception = context.Exception;

        if (exception is ArgumentNullException) 
        {
            message = ((ArgumentNullException)exception).ParamName + " is required";
            status = (int)HttpStatusCode.BadRequest;
        }

        if (exception is NotFoundException)
        {
            message = exception.Message;
            status = (int)HttpStatusCode.NotFound;
        }

        if (exception is AuthenticationException)
        {
            message = exception.Message;
            status = (int)HttpStatusCode.Unauthorized;
        }

        if (exception is DuplicateEntryException)
        {
            message = exception.Message;
            status = 422; // Unprocessable entity, not supported in HttpStatusCode class
        }

        HttpResponse response = context.HttpContext.Response;
        response.StatusCode = status;
        response.ContentType = "application/json";

        response.WriteAsync(JsonConvert.SerializeObject(new ErrorMessage(message, (int)status)));
    }
}

class ErrorMessage
{
    public string Message { get; set; }
    public int Code { get; set; }

    public ErrorMessage(string message, int code)
    {
        Message = message;
        Code = code;
    }
}

Integration test:

    [Fact]
    public async Task ItReturnsAnErrorWhenCredentialsAreIncorrect()
    {
        var request = new UserAuthenticationRequest();
        request.Username = "JohnDoe";
        request.Password = "TestPasswordIncorrect";

        var stringPayload = JsonConvert.SerializeObject(request);

        var httpContent = new StringContent(stringPayload, Encoding.UTF8, "application/json");

        _client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        var response = await _client.PostAsync("api/authentication/GetUserAppToken", httpContent);


        Assert.Equal(401, (int)response.StatusCode);
    }

Anyone having any idea why it is throwing the HttpRequestException?

Update:

Client setup:

    public AuthenticationControllerTest()
    {
        _testServer = new TestServer(new WebHostBuilder().UseStartup<TestStartup>());
        _client = _testServer.CreateClient();
    }

I did a test by setting up a new client per test method. Unfortunately that also didn't solve the problem

Update 2:

I think it has to do something with either the HttpClient setup or the request message I am sending. Instead of making use of the exception handler, I decided to return a BadRequest() from the controller right away.

    public BadRequestResult Post([FromBody]UserAuthenticationRequest userAuthenticationRequest)
    {
        return BadRequest();
    }

When doing that, I am getting a HttpRequestException again, instead of getting a HttpResponse with status code 400.

Frank Levering
  • 401
  • 3
  • 16
  • 1
    Check https://stackoverflow.com/a/35730278/5233410 – Nkosi Jul 14 '17 at 10:55
  • Please add the full exception message including the stack trace. – Yoh Deadfall Jul 14 '17 at 10:56
  • Can you include the code that sets up _client? Might not be related but given that this unit test is configuring the client instance (which appears to be shared between tests) by setting request headers are there other tests leaving the _client in a funky state? – dkackman Jul 14 '17 at 11:01
  • Also: use fiddler or something else while the test is running to ensure that the resulting message is being sent and if it is compare the request and response to what you see with Postman. Feels like your request message isn't right in some way. – dkackman Jul 14 '17 at 11:06
  • I have added the _client setup. The request message seems fine, since when I debugged the test it would go until the end. When I would write the response from the exception handler back to the client it seems to fail. – Frank Levering Jul 14 '17 at 12:02
  • @FrankLevering did you check the link i posted – Nkosi Jul 14 '17 at 12:06
  • @Nkosi Yes, I did. Unfortunately that didn't solve the problem since I am not reading as a stream or as a string anywhere during the request. – Frank Levering Jul 14 '17 at 12:10
  • @FrankLevering, Ok what I gathered from the answer is that because you are interacting with the stream directly in `response.WriteAsync` without awaiting there may be an issue. – Nkosi Jul 14 '17 at 12:14
  • @Nkosi please check my second update – Frank Levering Jul 14 '17 at 12:17
  • @FrankLevering Post the stack trace, so I will be able to check what's going wrong. – Yoh Deadfall Jul 14 '17 at 13:36

0 Answers0