简体   繁体   中英

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,

The problem is that you are telling the moq setup to use any http request message with: ItExpr.IsAny<HttpRequestMessage>() , so for any instance of HttpRequestMessage it will always return the same outcome.

If you a different X outcomes, you will need to create X different instances:

string firstUri = "http://testdoc.com/run?test=true&t2=10";
HttpRequestMessage httpRequestMessage_1 = new HttpRequestMessage
{
    RequestUri = new Uri(firstUri),
    Method = ...,
    Content = ...,
};

And instead of ItExpr.IsAny<HttpRequestMessage>() is that instance of httpRequestMessage_1 , with:

.Setup<Task<HttpResponseMessage>>("SendAsync", httpRequestMessage_1, ItExpr.IsAny<CancellationToken>())
.ReturnsAsync(new HttpResponseMessage
{  /* Something with X */ });

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;
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM