我正在调用外部API,并希望我的API可以进行单元测试。为此,我试图包装HttpClient。我现在只需要一种方法。 这是我的界面。
public interface IHttpClient
{
Task<string> GetStringAsync(string url);
}
这就是我实施它的方式。
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);
}
}
怀疑我有吗?这是正确的方法吗?设置bool参数会导致资源泄漏吗?关于HttpClient是否必须在每次通话中处理,我都读到了一些相互矛盾的想法。我接受了,但不是处置方,但我并不十分确定 如果有一种方法可以在没有包装器的情况下使用HttpClient但是使API可测试,那也会很棒。但到目前为止,我没能做到这一点。
谢谢, CleanKoder
答案 0 :(得分:3)
虽然为客户端创建一个接口仍然很好,但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)
});
}
}
如果您认为更适合您的项目,也可以使用像NSubstitute这样的隔离框架。