如何基于 URL 使用 Moq 对 HttpClient (HttpMessageHandler) 进行单元测试
How to unit test an HttpClient (HttpMessageHandler) with Moq based on the URL
致开发者,
我会模拟 HttpMessageHandler 来测试 HttpClient,我的问题是我将如何模拟基于
URL 和 Http 方法?所以响应将是方法和 URL:
的函数
Get + "http://testdoc.com/run?test=true&t2=10 => return X
Get + "http://testdoc.com/walk?test=true&t2=10 => return Y
Post + "http://testdoc.com/walk => return Z
所有 3 个调用都会 return 不同。
我当前的单元测试捕获了所有内容:
var mockMessageHandler = new Mock<HttpMessageHandler>();
mockMessageHandler.Protected()
.Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>())
.ReturnsAsync(new HttpResponseMessage
{ ... });
谢谢,
问题是您告诉最小起订量设置使用任何 http 请求消息:ItExpr.IsAny<HttpRequestMessage>()
,因此对于 HttpRequestMessage
的任何实例,它总是 return 相同的结果.
如果您有不同的 X 个结果,您将需要创建 X 个不同的实例:
string firstUri = "http://testdoc.com/run?test=true&t2=10";
HttpRequestMessage httpRequestMessage_1 = new HttpRequestMessage
{
RequestUri = new Uri(firstUri),
Method = ...,
Content = ...,
};
而不是 ItExpr.IsAny<HttpRequestMessage>()
是 httpRequestMessage_1
的实例,其中:
.Setup<Task<HttpResponseMessage>>("SendAsync", httpRequestMessage_1, ItExpr.IsAny<CancellationToken>())
.ReturnsAsync(new HttpResponseMessage
{ /* Something with X */ });
根据你的代码,我想出了下面的代码
模拟他们 URL.
识别的两个不同调用
var mockMessageHandler = new Mock<HttpMessageHandler>();
var content = new HttpContentMock(usersQueryResult);
content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");
mockMessageHandler.Protected()
.Setup<Task<HttpResponseMessage>>(
"SendAsync",
ItExpr.Is<HttpRequestMessage>(rm =>
rm.RequestUri.AbsoluteUri.StartsWith("https://example.com/api/users?query=")),
ItExpr.IsAny<CancellationToken>())
.ReturnsAsync(
new HttpResponseMessage
{
StatusCode = 200,
Content = content
};
);
mockMessageHandler.Protected()
.Setup<Task<HttpResponseMessage>>(
"SendAsync",
ItExpr.Is<HttpRequestMessage>(rm =>
rm.RequestUri.AbsoluteUri.StartsWith("https://example.com/api/users/gurka/")),
ItExpr.IsAny<CancellationToken>())
.ReturnsAsync(
new HttpResponseMessage
{
StatusCode = 201,
Content = null, // In reality the user found but we don't care for this test.
}
);
}
private class HttpContentMock : HttpContent
{
private readonly IList<AdUserDataContract> users;
public HttpContentMock(IList<AdUserDataContract> users)
{
this.users = users; }
protected override Task SerializeToStreamAsync(Stream stream, TransportContext context)
{
var json = JsonSerializer.Serialize(users, typeof(AdUsersDataContract));
var buffer = Encoding.ASCII.GetBytes(json);
stream.Write(buffer, 0, buffer.Length);
return Task.CompletedTask;
}
protected override bool TryComputeLength(out long length)
{
length = 1; // Well... not totally true is it?
return true;
}
}
致开发者, 我会模拟 HttpMessageHandler 来测试 HttpClient,我的问题是我将如何模拟基于 URL 和 Http 方法?所以响应将是方法和 URL:
的函数Get + "http://testdoc.com/run?test=true&t2=10 => return X
Get + "http://testdoc.com/walk?test=true&t2=10 => return Y
Post + "http://testdoc.com/walk => return Z
所有 3 个调用都会 return 不同。
我当前的单元测试捕获了所有内容:
var mockMessageHandler = new Mock<HttpMessageHandler>();
mockMessageHandler.Protected()
.Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>())
.ReturnsAsync(new HttpResponseMessage
{ ... });
谢谢,
问题是您告诉最小起订量设置使用任何 http 请求消息:ItExpr.IsAny<HttpRequestMessage>()
,因此对于 HttpRequestMessage
的任何实例,它总是 return 相同的结果.
如果您有不同的 X 个结果,您将需要创建 X 个不同的实例:
string firstUri = "http://testdoc.com/run?test=true&t2=10";
HttpRequestMessage httpRequestMessage_1 = new HttpRequestMessage
{
RequestUri = new Uri(firstUri),
Method = ...,
Content = ...,
};
而不是 ItExpr.IsAny<HttpRequestMessage>()
是 httpRequestMessage_1
的实例,其中:
.Setup<Task<HttpResponseMessage>>("SendAsync", httpRequestMessage_1, ItExpr.IsAny<CancellationToken>())
.ReturnsAsync(new HttpResponseMessage
{ /* Something with X */ });
根据你的代码,我想出了下面的代码
模拟他们 URL.
var mockMessageHandler = new Mock<HttpMessageHandler>();
var content = new HttpContentMock(usersQueryResult);
content.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");
mockMessageHandler.Protected()
.Setup<Task<HttpResponseMessage>>(
"SendAsync",
ItExpr.Is<HttpRequestMessage>(rm =>
rm.RequestUri.AbsoluteUri.StartsWith("https://example.com/api/users?query=")),
ItExpr.IsAny<CancellationToken>())
.ReturnsAsync(
new HttpResponseMessage
{
StatusCode = 200,
Content = content
};
);
mockMessageHandler.Protected()
.Setup<Task<HttpResponseMessage>>(
"SendAsync",
ItExpr.Is<HttpRequestMessage>(rm =>
rm.RequestUri.AbsoluteUri.StartsWith("https://example.com/api/users/gurka/")),
ItExpr.IsAny<CancellationToken>())
.ReturnsAsync(
new HttpResponseMessage
{
StatusCode = 201,
Content = null, // In reality the user found but we don't care for this test.
}
);
}
private class HttpContentMock : HttpContent
{
private readonly IList<AdUserDataContract> users;
public HttpContentMock(IList<AdUserDataContract> users)
{
this.users = users; }
protected override Task SerializeToStreamAsync(Stream stream, TransportContext context)
{
var json = JsonSerializer.Serialize(users, typeof(AdUsersDataContract));
var buffer = Encoding.ASCII.GetBytes(json);
stream.Write(buffer, 0, buffer.Length);
return Task.CompletedTask;
}
protected override bool TryComputeLength(out long length)
{
length = 1; // Well... not totally true is it?
return true;
}
}