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

如何在C中包装HttpClient以实现可测试性#,httpclient,asp.net-web-api,Httpclient,Asp.net Web Api,我正在调用一个外部API,希望我的API是可单元测试的。为了做到这一点,我正在尝试包装HttpClient。我现在只需要一种方法。 这是我的界面 public interface IHttpClient { Task<string> GetStringAsync(string url); } 公共接口IHttpClient { 任务GetStringAsync(字符串url); } 我就是这样实现的 公共类HttpClientWrapper:IHttpClient { 私

我正在调用一个外部API,希望我的API是可单元测试的。为了做到这一点,我正在尝试包装HttpClient。我现在只需要一种方法。 这是我的界面

public interface IHttpClient
{
    Task<string> GetStringAsync(string url);
}
公共接口IHttpClient
{
任务GetStringAsync(字符串url);
}
我就是这样实现的

公共类HttpClientWrapper:IHttpClient { 私有只读HttpClientu 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);
    }
公共HttpClientWrapper() { //我也可以注射这个,但我认为这会很好。 _httpClient=new-httpClient(new-HttpClientHandler(),false); } 公共异步任务GetStringAsync(字符串url) { //在此处验证url 返回wait_httpClient.GetStringAsync(url); } }

我有怀疑吗?这样做对吗?设置bool参数是否会导致资源泄漏?我读到了关于是否必须在每次通话中处理HttpClient的一些相互矛盾的观点。我接受了,虽然这不是我的观点,但我并不十分确定。
如果有一种方法可以在不使用包装器的情况下使用HttpClient,但使API可测试,那也将非常好。但到目前为止,我没能让它工作

谢谢,
CleanKoder

虽然为客户机创建一个接口仍然很好,但是
HttpClient
类实际上在设计时考虑了可测试性!实例化
HttpClient
时,可以插入自定义
HttpMessageHandler
。通过在这个类中重写
Task sendsync(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)
        });
    }
}
公共类FakeHttpMessageHandler:HttpMessageHandler
{
公共HttpRequestMessage LastRequest;
公共字符串LastRequestString=string.Empty;
公共字符串ResponseContent=string.Empty;
公共HttpStatusCode响应StatusCode=HttpStatusCode.OK;
受保护的覆盖异步任务SendAsync(HttpRequestMessage请求,
取消令牌(取消令牌)
{
if(request.Content!=null)
{
LastRequestString=wait request.Content.ReadAsStringAsync();
}
LastRequest=请求;
返回wait Task.FromResult(新的HttpResponseMessage
{
状态代码=响应状态代码,
内容=新的StringContent(ResponseContent)
});
}
}

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

在实际代码中传递什么?HttpMessageHandler是抽象的。我不知道它是否是默认构造函数中使用的,但在快速搜索之后,我会假设