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

use*_*435 6 httpclient asp.net-web-api

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

public interface IHttpClient
{
    Task<string> GetStringAsync(string url);
}
Run Code Online (Sandbox Code Playgroud)

这就是我实现它的方式.

public class HttpClientWrapper:IHttpClient {private readonly 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);
    }
Run Code Online (Sandbox Code Playgroud)

}

怀疑我有吗?这是正确的方法吗?设置bool参数会导致资源泄漏吗?关于HttpClient是否必须在每次通话中处理,我都读到了一些相互矛盾的想法.我采取了,但不是处置方,但我不是很确定.
如果有一种方法可以在没有包装器的情况下使用HttpClient但是使API可测试,那也会很棒.但到目前为止,我没能做到这一点.

谢谢,CleanKoder

sar*_*ara 5

虽然为客户端创建接口仍然很好,但HttpClient该类实际上是在设计时考虑了可测试性!实例化时,您HttpClient可以注入自定义HttpMessageHandler. 通过覆盖Task<HttpResponseMessage> 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)
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

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