【问题标题】:Mock HttpClient with many endpoints and large responses具有许多端点和大响应的模拟 HttpClient
【发布时间】:2022-01-11 02:57:53
【问题描述】:

我使用以下代码模拟HttpClientSendAsync 方法:

var mock = new Mock<HttpMessageHandler>();

Parallel.ForEach(endpoints, (e) =>
{
    mock
    .Protected()
    .Setup<Task<HttpResponseMessage>>(
        "SendAsync",
        ItExpr.Is<HttpRequestMessage>(
            x => x.RequestUri.AbsolutePath.Contains(e.Endpoint)),
        ItExpr.IsAny<CancellationToken>())
    .ReturnsAsync(() => new HttpResponseMessage()
    {
        Content = e.Response
    });
});

var client = new HttpClient(mock.Object);

其中endpoints 是以下类型的对象列表:

class Parameters
{
    public string Endpoint { get; }

    private readonly string _response;
    public StringContent Response
    {
        get { return new StringContent(_response); }
    }
}

这种模拟方法按预期工作,但有一个警告。在添加了相当数量的端点后,模拟受保护端点的速度显着下降。我需要为 ~5000 个端点模拟客户端,每个端点有 ~2MB 响应。 (为更少的端点和更小的数据设计测试似乎很棒,但不幸的是,在我的用例中不是一个选项)。增加了约 2k 个端点后,模拟速度显着下降。运行约 2 小时后,无法到达约 3k 端点。

我想知道是否有替代/更好的方法来模拟 HttpClient,理想情况下是线性渐近行为。

【问题讨论】:

  • 所有 2MB 响应是否相同?您是否重用用于_response 的字符串?您是否确保它在处理程序部分很慢,而不是在字符串生成部分?
  • Response 需要在对端点的每个 API 请求中成为基于 _response 的新实例,因此 _response 被重用于对端点的不同调用。我还没有完成 CPU 分析,因此无法确定它在处理程序或字符串生成时是否变得越来越慢。

标签: c# unit-testing mocking httpclient moq


【解决方案1】:

您是否尝试通过覆盖 HttpMessageHandler 来消除 Mock 开销?

其他潜在的瓶颈是匹配请求 URL 和端点响应的 Mock 代码。对于大量端点,优化它确实有意义(例如 MockHttpMessageHandler.SendAsync() 使用 Dictionary 或 Lookup 来查找响应)。

public class MockHttpMessageHandler : HttpMessageHandler
{
    private readonly Dictionary<string, HttpContent> _endpoints;

    public MockHttpMessageHandler(Dictionary<string, HttpContent> endpoints)
    {
        _endpoints = endpoints;
    }
    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        if (_endpoints.TryGetValue(request.RequestUri.ToString(), out var content))
            return Task.FromResult(new HttpResponseMessage() { Content = content });

        return Task.FromResult(new HttpResponseMessage() { StatusCode = HttpStatusCode.NotFound });
    }
}

【讨论】:

  • 这是一个很好的建议,虽然我不确定你如何使用它来模拟端点。
猜你喜欢
  • 1970-01-01
  • 2022-11-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-08-12
  • 2011-06-24
  • 1970-01-01
相关资源
最近更新 更多