Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to unit test an HttpClient (HttpMessageHandler) with Moq based on the URL

To Devs, I would be mocking HttpMessageHandler to test an HttpClient, my question is how would I mock based on the URL and Http Method? So the response would be a function of the Method and URL:

Get + "http://testdoc.com/run?test=true&t2=10   => return X
Get + "http://testdoc.com/walk?test=true&t2=10   => return Y
Post + "http://testdoc.com/walk   => return Z

All 3 calls would return something different.

My current unit test catches everything:

var mockMessageHandler = new Mock<HttpMessageHandler>();
mockMessageHandler.Protected()
    .Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>())
    .ReturnsAsync(new HttpResponseMessage
    {  ... });

Thanks,

like image 540
user1154422 Avatar asked Sep 16 '25 15:09

user1154422


1 Answers

Based on your code I came up with the code below
that mocks two different calls recognised by their URL.

var mockMessageHandler = new Mock<HttpMessageHandler>();

var content = new HttpContentMock(usersQueryResult);
content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");

mockMessageHandler.Protected()
  .Setup<Task<HttpResponseMessage>>(
    "SendAsync",
    ItExpr.Is<HttpRequestMessage>(rm => 
      rm.RequestUri.AbsoluteUri.StartsWith("https://example.com/api/users?query=")),
    ItExpr.IsAny<CancellationToken>())
    .ReturnsAsync(
      new HttpResponseMessage
      {
        StatusCode = 200,
        Content = content
      };
    );

mockMessageHandler.Protected()
  .Setup<Task<HttpResponseMessage>>(
    "SendAsync",
    ItExpr.Is<HttpRequestMessage>(rm => 
      rm.RequestUri.AbsoluteUri.StartsWith("https://example.com/api/users/gurka/")),
    ItExpr.IsAny<CancellationToken>())
  .ReturnsAsync(
    new HttpResponseMessage
    {
      StatusCode = 201,
      Content = null, // In reality the user found but we don't care for this test.
    }
  );
}

private class HttpContentMock : HttpContent
{
  private readonly IList<AdUserDataContract> users;
  public HttpContentMock(IList<AdUserDataContract> users)
  {
    this.users = users;  }

  protected override Task SerializeToStreamAsync(Stream stream, TransportContext context)
  {
    var json = JsonSerializer.Serialize(users, typeof(AdUsersDataContract));
    var buffer = Encoding.ASCII.GetBytes(json);
    stream.Write(buffer, 0, buffer.Length);
    return Task.CompletedTask;
  }

  protected override bool TryComputeLength(out long length)
  {
    length = 1; // Well... not totally true is it?
    return true;
  }
}
like image 169
LosManos Avatar answered Sep 19 '25 05:09

LosManos