调用 PostAsync 后测试 HttpRequestMessage.Content 的值
Posted
技术标签:
【中文标题】调用 PostAsync 后测试 HttpRequestMessage.Content 的值【英文标题】:Test the value of the HttpRequestMessage.Content after calling PostAsync 【发布时间】:2017-01-19 02:08:58 【问题描述】:我们已经模拟了HttpMessageHandler
,因此我们可以测试一个使用HttpClient
的类。
我们正在测试的一个方法创建一个新的HttpClient
,调用PostAsync
,并释放HttpClient
。我们想像这样测试 HTTP 请求的Content
:
Assert.Equal("", ActualHttpRequestMessage.Content.ReadAsStringAsync());
问题是我们“无法访问已处置的对象”,因为the HttpClient
disposes the Content
。
问题我们如何检查内容?
这是我们的起订量设置。
MockHttpMessageHandler = new Mock<HttpMessageHandler>();
MockHttpMessageHandler
.Protected()
.Setup<Task<HttpResponseMessage>>(
"SendAsync",
ItExpr.IsAny<HttpRequestMessage>(),
ItExpr.IsAny<CancellationToken>())
.Callback<HttpRequestMessage, CancellationToken>(
(httpRequestMessage, cancellationToken) =>
ActualHttpRequestMessage = httpRequestMessage;
)
.Returns(
Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK)
Content = new StringContent(string.Empty)
));
这就是我们在被测类中使用它的方式。
new HttpClient(HttpMessageHandler);
【问题讨论】:
我不会添加这个作为答案,因为它是我自己的库,但你看过MockHttp 吗?与 Moq 等动态模拟库相比,它为模拟 HttpClient 请求提供了更好的 DSL。 【参考方案1】:将你的模拟更改为:
MockHttpMessageHandler
.Protected()
.Setup<Task<HttpResponseMessage>>(
"SendAsync",
ItExpr.IsAny<HttpRequestMessage>(),
ItExpr.IsAny<CancellationToken>())
.Callback<HttpRequestMessage, CancellationToken>(
(httpRequestMessage, cancellationToken) =>
// +++++++++++++++++++++++++++++++++++++++++
// Read the Content here before it's disposed
ActualHttpRequestContent = httpRequestMessage.Content
.ReadAsStringAsync()
.GetAwaiter()
.GetResult();
ActualHttpRequestMessage = httpRequestMessage;
)
.Returns(
Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK)
Content = new StringContent(string.Empty)
));
然后你可以这样测试:
Assert.Equal("", ActualHttpRequestContent);
请记住,我们只能读取一次Content
,因此如果您稍后尝试读取它,它将是空的。它就像一个海森堡物体。
【讨论】:
处理内容的不是我们的测试方法。我们正在测试的方法正在这样做。我们的测试方法是调用HttpClient.PostAsync
,它会自动处理HttpResponseMessage.Content
。
我很抱歉。我以为你指的是响应消息。为什么您的单元测试需要在发布后检查请求内容?事先检查一下。发布它不会更改请求内容。 (或者 - 您的单元测试正在检查请求,但您的评论指的是响应)
我们如何在发布前对其进行检查?
您的断言正在测试 ActualHttpRequestMessage.Content。如果您真的想对请求进行单元测试,那么您就是设置内容的人。你确定不应该是 ActualHttpResponseMessage.Content 吗?
是的。我们想测试我们发送的请求。我们不关心回应。基本上,被测方法接受一堆参数,将它们变成HttpClient
请求,然后调用PostAsync
。我们想测试帖子内容是否应有。以上是关于调用 PostAsync 后测试 HttpRequestMessage.Content 的值的主要内容,如果未能解决你的问题,请参考以下文章
调用 HTTPClient.PostAsync 时设置 Authorization/Content-Type 标头