使用Moq模拟HttpClient [英] Mock HttpClient using Moq
问题描述
我喜欢对使用HttpClient
的类进行单元测试.我们将HttpClient
对象注入到类构造函数中.
I like to unit test a class that use HttpClient
. We injected the HttpClient
object in the class constructor.
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;
}
}
现在,我们想对ClassA.SendRequest
方法进行单元测试.我们将Ms Test
用于单元测试框架,并将Moq
用于模拟.
Now we like to unit test the ClassA.SendRequest
method. We are using Ms Test
for unit testing framework and Moq
for mocking.
当我们尝试模拟HttpClient
时,它会抛出NotSupportedException
.
When we tried to mock the HttpClient
, it throws NotSupportedException
.
[TestMethod]
public async Task SendRequestAsync_Test()
{
var mockHttpClient = new Mock<HttpClient>();
mockHttpClient.Setup(
m => m.SendAsync(It.IsAny<HttpRequestMessage>()))
.Returns(() => Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK)));
}
我们如何解决这个问题?
How can we solve this issue?
推荐答案
该特定的重载方法不是虚拟的,因此无法被Moq覆盖.
That particular overload method is not virtual so is unable to be overridden by Moq.
public Task<HttpResponseMessage> SendAsync(HttpRequestMessage request);
这就是为什么它抛出NotSupportedException
您正在寻找的虚拟方法就是这种方法
The virtual method you are looking for is this method
public virtual Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken);
但是模拟HttpClient
并不像使用其内部消息处理程序那样简单.
However mocking HttpClient
is not as simple as it seems with its internal message handler.
我建议使用带有自定义消息处理程序存根的具体客户端,以便在伪造请求时提供更大的灵活性.
I suggest using a concrete client with a custom message handler stub that will allow for more flexibility when faking the request.
这里是委派处理程序存根的示例.
Here is an example of a delegating handler stub.
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);
}
}
请注意,默认构造函数基本上是在做您以前尝试模仿的事情.它还允许带有请求委托的更多自定义方案.
Note the default constructor is doing basically what you were trying to mock before. It also allows for more custom scenarios with a delegate for the request.
使用存根,可以将测试重构为类似的内容
With the stub, the test can be refactored to something like
public async Task _SendRequestAsync_Test() {
//Arrange
var handlerStub = new DelegatingHandlerStub();
var client = new HttpClient(handlerStub);
var sut = new ClassA(client);
var obj = new SomeObject() {
//Populate
};
//Act
var response = await sut.SendRequest(obj);
//Assert
Assert.IsNotNull(response);
Assert.IsTrue(response.IsSuccessStatusCode);
}
这篇关于使用Moq模拟HttpClient的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!