如何在 C# 中包装 HttpClient 以实现可测试性

Posted

技术标签:

【中文标题】如何在 C# 中包装 HttpClient 以实现可测试性【英文标题】:How to wrap HttpClient for testability in C# 【发布时间】:2014-07-09 00:12:46 【问题描述】:

我正在调用一个外部 API,并且希望我的 API 可以进行单元测试。为此,我正在尝试包装 HttpClient。我现在只需要一种方法。 这是我的界面。

public interface IHttpClient

    Task<string> GetStringAsync(string url);

这就是我实现它的方式。

公共类 HttpClientWrapper : IHttpClient 私有只读HttpClient _httpClient;

    public HttpClientWrapper()
    
        // I could also inject this but I think this will be fine as is. 
        _httpClient = new HttpClient(new HttpClientHandler(), false);
    

    public async Task<string> GetStringAsync(string url)
    
        //validate url here
        return await _httpClient.GetStringAsync(url);
    

我有疑问吗?这是正确的方法吗?设置 bool 参数会导致这里的资源泄漏吗?我读到了一些关于是否必须在每次调用时处理 HttpClient 的相互矛盾的想法。我接受了,不处理的一面,但不是很确定。 如果有一种方法可以在没有包装器的情况下使用 HttpClient 但使 API 可测试,那也很棒。但到目前为止,我没能成功。

谢谢, CleanKoder

【问题讨论】:

【参考方案1】:

虽然为客户端创建接口仍然很好,但HttpClient 类实际上在设计时考虑了可测试性!当实例化你的HttpClient 时,你可以注入一个自定义的HttpMessageHandler。通过在此类中覆盖 Task&lt;HttpResponseMessage&gt; SendAsync(HttpRequestMessage request, CancellationToken cancellationToken),您可以在所有请求实际写入套接字之前中断所有请求,检查它们并返回您认为合适的任何内容。

这是我在项目中编写的此类测试替身的示例,请随意修改以适应您的需求:

public class FakeHttpMessageHandler : HttpMessageHandler

    public HttpRequestMessage LastRequest;
    public string LastRequestString = string.Empty;
    public string ResponseContent = string.Empty;
    public HttpStatusCode ResponseStatusCode = HttpStatusCode.OK;

    protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
        CancellationToken cancellationToken)
    
        if (request.Content != null)
        
            LastRequestString = await request.Content.ReadAsStringAsync();
        
        LastRequest = request;
        return await Task.FromResult(new HttpResponseMessage
        
            StatusCode = ResponseStatusCode,
            Content = new StringContent(ResponseContent)
        );
    

如果您认为更适合您的项目,也可以使用 NSubstitute 之类的隔离框架。

【讨论】:

你在真实代码中传递了什么? HttpMessageHandler 是抽象的。 我不知道它是否是默认构造函数中使用的,但经过快速搜索我会假设msdn.microsoft.com/en-us/library/…

以上是关于如何在 C# 中包装 HttpClient 以实现可测试性的主要内容,如果未能解决你的问题,请参考以下文章

如何访问由 C# 中包装的非.net API 返回的数组?

如何在 AppBar 中包装子小部件以获得更大的子高度和 Flutter 中的填充

如何使用 .Net 4.0 中包含的 HttpClient 类将文件上传到在 IIS Express 中运行的 Asp.Net MVC 4.0 操作

C# 9+ 中的 HttpClient 空警告

C# 中 HttpClient 的 JSON 有效负载?

如何使用 C# HttpClient PostAsync 显示上传进度