C# 使用Moq模拟HttpClient
我想对使用C# 使用Moq模拟HttpClient,c#,unit-testing,moq,mstest,dotnet-httpclient,C#,Unit Testing,Moq,Mstest,Dotnet Httpclient,我想对使用HttpClient的类进行单元测试。我们在类构造函数中注入了HttpClient对象 public class ClassA : IClassA { private readonly HttpClient _httpClient; public ClassA(HttpClient httpClient) { _httpClient = httpClient; } public async Task<HttpRespon
HttpClient
的类进行单元测试。我们在类构造函数中注入了HttpClient
对象
public class ClassA : IClassA
{
private readonly HttpClient _httpClient;
public ClassA(HttpClient httpClient)
{
_httpClient = httpClient;
}
public async Task<HttpResponseMessage> SendRequest(SomeObject someObject)
{
//Do some stuff
var request = new HttpRequestMessage(HttpMethod.Post, "http://some-domain.in");
//Build the request
var response = await _httpClient.SendAsync(request);
return response;
}
}
我们如何解决这个问题?特定的重载方法不是虚拟的,因此无法被Moq覆盖
public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request);
然而,模仿HttpClient并不像内部消息处理程序那样简单
我建议使用带有自定义消息处理程序存根的具体客户机,这将在伪造请求时提供更大的灵活性
下面是一个委托处理程序存根的示例
public class DelegatingHandlerStub : DelegatingHandler {
private readonly Func<HttpRequestMessage, CancellationToken, Task<HttpResponseMessage>> _handlerFunc;
public DelegatingHandlerStub() {
_handlerFunc = (request, cancellationToken) => Task.FromResult(request.CreateResponse(HttpStatusCode.OK));
}
public DelegatingHandlerStub(Func<HttpRequestMessage, CancellationToken, Task<HttpResponseMessage>> handlerFunc) {
_handlerFunc = handlerFunc;
}
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) {
return _handlerFunc(request, cancellationToken);
}
}
Propper使用HttpClient进行模拟是一项艰苦的工作,因为它是在大多数人在dotnet中进行单元测试之前编写的。有时,我会设置一个存根HTTP服务器,根据与请求url匹配的模式返回固定响应,这意味着您测试的是真正的HTTP请求,而不是模拟,而是本地主机服务器。使用使这变得非常简单,并且运行速度足够快,可以满足我的大部分单元测试需求 因此,与其使用
http://some-domain.in
在某些端口上使用本地主机服务器设置,然后:
var server = FluentMockServer.Start(/*server and port can be setup here*/);
server.Given(
Request.Create()
.WithPath("/").UsingPost()
)
.RespondWith(
Response.Create()
.WithStatusCode(200)
.WithHeader("Content-Type", "application/json")
.WithBody("{'attr':'value'}")
);
您可以找到更多详细信息,Moq可以模拟受保护的方法,例如HttpMessageHandler上的SendAsync,您可以在其构造函数中提供给HttpClient
public class ClassA : IClassA
{
private readonly HttpClient _httpClient;
public ClassA(HttpClient httpClient)
{
_httpClient = httpClient;
}
public async Task<HttpResponseMessage> SendRequest(SomeObject someObject)
{
//Do some stuff
var request = new HttpRequestMessage(HttpMethod.Post, "http://some-domain.in");
//Build the request
var response = await _httpClient.SendAsync(request);
return response;
}
}
var mockHttpMessageHandler=new Mock();
mockHttpMessageHandler.Protected()
.Setup(“sendsync”、ItExpr.IsAny()、ItExpr.IsAny())
.ReturnsAsync(新的HttpResponseMessage
{
StatusCode=HttpStatusCode.OK
});
var client=新的HttpClient(mockHttpMessageHandler.Object);
抄袭自我最近不得不模仿HttpClient,我使用了。这正是我所需要的,而且使用简单,所以我想我应该把它扔掉 以下是一般用法的示例:
// All requests made with HttpClient go through its handler's SendAsync() which we mock
var handler = new Mock<HttpMessageHandler>();
var client = handler.CreateClient();
// A simple example that returns 404 for any request
handler.SetupAnyRequest()
.ReturnsResponse(HttpStatusCode.NotFound);
// Match GET requests to an endpoint that returns json (defaults to 200 OK)
handler.SetupRequest(HttpMethod.Get, "https://example.com/api/stuff")
.ReturnsResponse(JsonConvert.SerializeObject(model), "application/json");
// Setting additional headers on the response using the optional configure action
handler.SetupRequest("https://example.com/api/stuff")
.ReturnsResponse(bytes, configure: response =>
{
response.Content.Headers.LastModified = new DateTime(2018, 3, 9);
})
.Verifiable(); // Naturally we can use Moq methods as well
// Verify methods are provided matching the setup helpers
handler.VerifyAnyRequest(Times.Exactly(3));
//使用HttpClient发出的所有请求都会通过其处理程序的SendAsync()进行模拟
var handler=newmock();
var client=handler.CreateClient();
//一个简单的示例,对于任何请求都返回404
handler.SetupAnyRequest()
.ReturnsResponse(HttpStatusCode.NotFound);
//将GET请求与返回json的端点匹配(默认为200 OK)
handler.SetupRequest(HttpMethod.Get)https://example.com/api/stuff")
.ReturnsResponse(JsonConvert.SerializeObject(模型),“应用程序/json”);
//使用可选的配置操作在响应上设置其他标头
handler.SetupRequest(“https://example.com/api/stuff")
.ReturnsResponse(字节,配置:响应=>
{
response.Content.Headers.LastModified=新日期时间(2018年3月9日);
})
.Verifiable();//当然,我们也可以使用最小起重量法
//验证是否提供了与设置帮助程序匹配的方法
handler.VerifyAnyRequest(Times.justice(3));
有关更多信息,请查看作者的博客文章
var server = FluentMockServer.Start(/*server and port can be setup here*/);
server.Given(
Request.Create()
.WithPath("/").UsingPost()
)
.RespondWith(
Response.Create()
.WithStatusCode(200)
.WithHeader("Content-Type", "application/json")
.WithBody("{'attr':'value'}")
);
// All requests made with HttpClient go through its handler's SendAsync() which we mock
var handler = new Mock<HttpMessageHandler>();
var client = handler.CreateClient();
// A simple example that returns 404 for any request
handler.SetupAnyRequest()
.ReturnsResponse(HttpStatusCode.NotFound);
// Match GET requests to an endpoint that returns json (defaults to 200 OK)
handler.SetupRequest(HttpMethod.Get, "https://example.com/api/stuff")
.ReturnsResponse(JsonConvert.SerializeObject(model), "application/json");
// Setting additional headers on the response using the optional configure action
handler.SetupRequest("https://example.com/api/stuff")
.ReturnsResponse(bytes, configure: response =>
{
response.Content.Headers.LastModified = new DateTime(2018, 3, 9);
})
.Verifiable(); // Naturally we can use Moq methods as well
// Verify methods are provided matching the setup helpers
handler.VerifyAnyRequest(Times.Exactly(3));