我正在尝试在我的应用中正确添加HttpClient
,同时还允许出于单元测试目的而模拟掉客户端工厂。我使用this作为资源。
在我的 Startup.cs
中services.AddHttpClient<IUploader, Uploader>()
.ConfigurePrimaryHttpMessageHandler(() =>
{
if (somecheckismet)
return new HttpClientHandler() { ServerCertificateCustomValidationCallback = delegate { return true; } };
return new HttpClientHandler();
});
还有我的 Uploader.cs
public class Uploader : IUploader
{
private readonly HttpClient m_httpClient;
public Uploader(HttpClient client)
{
m_httpClient = client;
}
public async Task<string> UploadData(string url, Dictionary<string, string> data)
{
HttpResponseMessage result;
try
{
result = await m_httpClient.PostAsync(url, new FormUrlEncodedContent(data));
if (result.StatusCode != HttpStatusCode.OK)
{
return "Some error message;
}
else
{
return null; // Success!
}
}
catch (Exception ex)
{
return "Uh-oh!";
}
}
}
如您所见,我正在尝试将HttpClient
依赖注入Uploader
中。但是,既然已经完成了,如何进行Uploader
的单元测试?以前,它可以用来依赖注入HttpClientHandler
,而后者可以被嘲笑掉。但是,由于我现在尝试使用IHttpClientFactory
,因此似乎必须注入HttpClient
。
任何帮助将不胜感激。
答案 0 :(得分:0)
似乎您可以继续模拟HttpClientHandler
并使用它来创建HttpClient
public void TestMethod()
{
var handler = // Mock the HttpClientHandler;
var client = new HttpClient(handler);
var uploader = new Uploader(client);
// Draw the rest of the owl
}
答案 1 :(得分:0)
您实际上不需要先定下HttpClientFactory
。 HttpClientFactory
只是一个帮助程序类,它从池中返回HttpClient
个实例。在单元测试方案中,您将直接设置HttpClient
实例。 startup.cs永远不会输入图片,因为您没有启动整个应用程序。
您的Uploader
类已经为单元测试设置了,因为您正在传递HttpClient
实例。要围绕HttpClient
进行单元测试,您无需先提出HttpClient
实例,而要替换HttpMessageHandler
使用的HttpClient
。
这是有关所有详细信息的link精彩文章
直接从文章中提取代码
// ARRANGE
var handlerMock = new Mock<HttpMessageHandler>(MockBehavior.Strict);
handlerMock
.Protected()
// Setup the PROTECTED method to mock
.Setup<Task<HttpResponseMessage>>(
"SendAsync",
ItExpr.IsAny<HttpRequestMessage>(),
ItExpr.IsAny<CancellationToken>()
)
// prepare the expected response of the mocked http call
.ReturnsAsync(new HttpResponseMessage()
{
StatusCode = HttpStatusCode.OK,
Content = new StringContent("[{'id':1,'value':'1'}]"),
})
.Verifiable();
// use real http client with mocked handler here
var httpClient = new HttpClient(handlerMock.Object)
{
BaseAddress = new Uri("http://test.com/"),
};
var subjectUnderTest = new MyTestClass(httpClient);
// ACT
var result = await subjectUnderTest
.GetSomethingRemoteAsync('api/test/whatever');
// ASSERT
result.Should().NotBeNull(); // this is fluent assertions here...
result.Id.Should().Be(1);
// also check the 'http' call was like we expected it
var expectedUri = new Uri("http://test.com/api/test/whatever");
handlerMock.Protected().Verify(
"SendAsync",
Times.Exactly(1), // we expected a single external request
ItExpr.Is<HttpRequestMessage>(req =>
req.Method == HttpMethod.Get // we expected a GET request
&& req.RequestUri == expectedUri // to this uri
),
ItExpr.IsAny<CancellationToken>()
);