Mock HttpClientFactory 使用 Moq Framework 创建模拟的 HttpClient
Mock HttpClientFactory to create a mocked HttpClient Using Moq Framework
我有一个方法,其中包含创建 HttpClient
的 HttpClientFactory
。该方法调用其中的 SendAsync
方法。我需要操纵 SendAsync
方法来向我发送一条成功消息,无论它作为参数是什么。
我想测试这个方法
public class TestService
{
private readonly IHttpClientFactory _clientFactory;
public TestService(IHttpClientFactory clientFactory)
{
_clientFactory = clientFactory;
}
public async Task<bool> TestMethod(string testdata)
{
var message = new HttpRequestMessage(); //SIMPLIFIED CODE
var client = _clientFactory.CreateClient();
var response = await client.SendAsync(message);
if(response.IsSuccessStatusCode){
return true;
}else{
return false;
}
}
}
我尝试的是
private readonly Mock<IHttpClientFactory> _mockHttpClientFactory;
private readonly Mock<HttpClient> _mockHttpClient;
[Fact]
public void TestMethod_ValidHttpRequest_ReturnsTrue()
{
var httpClient = _mockHttpClient
.Setup(x => x.SendAsync(It.IsAny<HttpRequestMessage>()))
.ReturnsAsync(new HttpResponseMessage()
{
StatusCode = HttpStatusCode.OK,
Content = new StringContent("[{'id':1,'value':'1'}]"),
});
var client = _mockHttpClientFactory.Setup(x => x.CreateClient()).Returns(httpClient); //DOESNT WORK
var service = new TestService(_mockHttpClientFactory);
var result = service.TestMethod("testdata");
Assert.True(result.Result)
}
我建议查看来自 Gingster Ale 的以下博客 post。作者的这个示例向您展示了如何模拟对 HttpClient 的调用:
// ARRANGE
var handlerMock = new Mock<HttpMessageHandler>(MockBehavior.Strict);
handlerMock
.Protected()
// Setup the PROTECTED method to mock
.Setup<Task<HttpResponseMessage>>(
"SendAsync",
ItExpr.IsAny<HttpRequestMessage>(),
ItExpr.IsAny<CancellationToken>()
)
// prepare the expected response of the mocked http call
.ReturnsAsync(new HttpResponseMessage()
{
StatusCode = HttpStatusCode.OK,
Content = new StringContent("[{'id':1,'value':'1'}]"),
})
.Verifiable();
// use real http client with mocked handler here
var httpClient = new HttpClient(handlerMock.Object)
{
BaseAddress = new Uri("http://test.com/"),
};
var subjectUnderTest = new MyTestClass(httpClient);
// ACT
var result = await subjectUnderTest
.GetSomethingRemoteAsync('api/test/whatever');
// ASSERT
result.Should().NotBeNull(); // this is fluent assertions here...
result.Id.Should().Be(1);
// also check the 'http' call was like we expected it
var expectedUri = new Uri("http://test.com/api/test/whatever");
handlerMock.Protected().Verify(
"SendAsync",
Times.Exactly(1), // we expected a single external request
ItExpr.Is<HttpRequestMessage>(req =>
req.Method == HttpMethod.Get // we expected a GET request
&& req.RequestUri == expectedUri // to this uri
),
ItExpr.IsAny<CancellationToken>()
);
此外,如果您可以自由使用 HttpClient 以外的其他东西,我建议您查看 Flurl。
我有一个方法,其中包含创建 HttpClient
的 HttpClientFactory
。该方法调用其中的 SendAsync
方法。我需要操纵 SendAsync
方法来向我发送一条成功消息,无论它作为参数是什么。
我想测试这个方法
public class TestService
{
private readonly IHttpClientFactory _clientFactory;
public TestService(IHttpClientFactory clientFactory)
{
_clientFactory = clientFactory;
}
public async Task<bool> TestMethod(string testdata)
{
var message = new HttpRequestMessage(); //SIMPLIFIED CODE
var client = _clientFactory.CreateClient();
var response = await client.SendAsync(message);
if(response.IsSuccessStatusCode){
return true;
}else{
return false;
}
}
}
我尝试的是
private readonly Mock<IHttpClientFactory> _mockHttpClientFactory;
private readonly Mock<HttpClient> _mockHttpClient;
[Fact]
public void TestMethod_ValidHttpRequest_ReturnsTrue()
{
var httpClient = _mockHttpClient
.Setup(x => x.SendAsync(It.IsAny<HttpRequestMessage>()))
.ReturnsAsync(new HttpResponseMessage()
{
StatusCode = HttpStatusCode.OK,
Content = new StringContent("[{'id':1,'value':'1'}]"),
});
var client = _mockHttpClientFactory.Setup(x => x.CreateClient()).Returns(httpClient); //DOESNT WORK
var service = new TestService(_mockHttpClientFactory);
var result = service.TestMethod("testdata");
Assert.True(result.Result)
}
我建议查看来自 Gingster Ale 的以下博客 post。作者的这个示例向您展示了如何模拟对 HttpClient 的调用:
// ARRANGE
var handlerMock = new Mock<HttpMessageHandler>(MockBehavior.Strict);
handlerMock
.Protected()
// Setup the PROTECTED method to mock
.Setup<Task<HttpResponseMessage>>(
"SendAsync",
ItExpr.IsAny<HttpRequestMessage>(),
ItExpr.IsAny<CancellationToken>()
)
// prepare the expected response of the mocked http call
.ReturnsAsync(new HttpResponseMessage()
{
StatusCode = HttpStatusCode.OK,
Content = new StringContent("[{'id':1,'value':'1'}]"),
})
.Verifiable();
// use real http client with mocked handler here
var httpClient = new HttpClient(handlerMock.Object)
{
BaseAddress = new Uri("http://test.com/"),
};
var subjectUnderTest = new MyTestClass(httpClient);
// ACT
var result = await subjectUnderTest
.GetSomethingRemoteAsync('api/test/whatever');
// ASSERT
result.Should().NotBeNull(); // this is fluent assertions here...
result.Id.Should().Be(1);
// also check the 'http' call was like we expected it
var expectedUri = new Uri("http://test.com/api/test/whatever");
handlerMock.Protected().Verify(
"SendAsync",
Times.Exactly(1), // we expected a single external request
ItExpr.Is<HttpRequestMessage>(req =>
req.Method == HttpMethod.Get // we expected a GET request
&& req.RequestUri == expectedUri // to this uri
),
ItExpr.IsAny<CancellationToken>()
);
此外,如果您可以自由使用 HttpClient 以外的其他东西,我建议您查看 Flurl。