我使用HttpClient获得以下代码。我是C#的新手,想学习如何对HttpClient进行单元测试,但不确定从哪里开始。这是我的代码:
protected override async Task PopulateData()
{
using (var client = new HttpClient())
{
var token = "private token";
var requestUrl = api_url_here;
var authenticatedRequestUrl = requestUrl + $"{token}";
var response = await client.GetAsync(authenticatedRequestUrl);
var stringResult = await response.Content.ReadAsStringAsync();
// do something
}
}
我看过很多不同的文章,它们提出了不同的单元测试方法,但是我不确定如何正确使用它们。例如,我在许多网站上都看到过这种单元测试模式:
[Test]
public async Task MockingHTTP()
{
var requestUri = new Uri("");
var expectedResponse = "Response";
var mockHandler = new Mock<HttpMessageHandler>();
mockHandler.Protected()
.Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(),
ItExpr.IsAny<CancellationToken>())
.ReturnsAsync(new HttpResponseMessage(Net.HttpStatusCode.OK));
var httpClient = new HttpClient(mockHandler.Object);
var result = await httpClient.GetStringAsync(requestUri).ConfigureAwait(false);
Assert.AreEqual(expectedResponse, result);
}
}
但是我不知道如何将这种方法应用于我的代码。请有人指出我的正确方向,以便成功地对HttpClient进行单元测试?
答案 0 :(得分:2)
单元测试时要做的第一件事是识别“被测系统”或SUT。那就是您需要验证其行为的东西。 SUT的所有依赖项都应被模拟,不应使用真实版本。
在这种情况下,您使用的是HttpClient,但是您无法在方法中使用其他处理程序。使用不同的处理程序是为HttpClient伪造响应的最简单方法。 HttpClient通过构造函数接受其他处理程序。因此,您需要像这样调整代码:
public class YourClassName
{
private readonly HttpMessageHandler _httpMessageHandler;
public YourClassName(HttpMessageHandler httpMessageHandler)
{
_httpMessageHandler = httpMessageHandler;
}
protected override async Task PopulateData()
{
using (var client = new HttpClient(_httpMessageHandler))
{
var token = "private token";
var requestUrl = api_url_here;
var authenticatedRequestUrl = requestUrl + $"{token}";
var response = await client.GetAsync(authenticatedRequestUrl);
var stringResult = await response.Content.ReadAsStringAsync();
// do something
}
}
}
现在它是可单元测试的,因为您可以模拟HttpMessageHandler。但是执行此操作的代码是cumbersome。考虑到使用HttpClient的其他缺陷,最好一开始甚至不要使用HttpClient。参见:
我的团队所做的是改用Flurl。它具有更好的语法,不具有HttpClient具有的IDisposable的怪异特性,并且易于进行单元测试。
protected override async Task PopulateData()
{
var token = "private token";
var requestUrl = api_url_here;
var authenticatedRequestUrl = requestUrl + $"{token}";
var stringResult = authenticatedRequestUrl.
var response = await authenticatedRequestUrl.GetAsync();
var stringResult = await response.Content.ReadAsStringAsync();
// do something
}
然后您的单元测试变得更加简单:
[Test]
public async Task PopulateDataTest()
{
var requestUri = new Uri("SomeUriWithAToken");
var expectedResponse = "some response body";
var systemUnderTest = new YourClassName();
using (var httpTest = new HttpTest())
{
httpTest.RespondWith(expectedResponse);
var result = await systemUnderTest.PopulateData();
Assert.AreEqual(expectedResponse, result);
httpTest.ShouldHaveCalled(requestUri);
}
}
Flurl的文档很棒。您可以让它返回各种响应,甚至可以自动反序列化对C#类的响应。