c# - 如何使用 Moq 在 .NET Core 2.1 中模拟新的 HttpClientFactory
问题描述
.NET Core 2.1 附带了这个名为 的新工厂HttpClientFactory
,但我不知道如何模拟它来对包括 REST 服务调用的一些方法进行单元测试。
工厂正在使用 .NET Core IoC 容器注入,该方法的作用是从工厂创建一个新客户端:
var client = _httpClientFactory.CreateClient();
然后使用客户端从 REST 服务获取数据:
var result = await client.GetStringAsync(url);
解决方案
HttpClientFactory
是从IHttpClientFactory
Interface派生的所以只需要创建一个接口的mock
var mockFactory = new Mock<IHttpClientFactory>();
根据您需要客户端的用途,您需要设置模拟以返回HttpClient
测试。
然而,这需要一个实际的HttpClient
.
var clientHandlerStub = new DelegatingHandlerStub();
var client = new HttpClient(clientHandlerStub);
mockFactory.Setup(_ => _.CreateClient(It.IsAny<string>())).Returns(client);
IHttpClientFactory factory = mockFactory.Object;
然后可以在执行测试时将工厂注入到被测依赖系统中。
如果您不希望客户端调用实际端点,那么您将需要创建一个假委托处理程序来拦截请求。
用于伪造请求的处理程序存根示例
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);
}
}
取自我在这里给出的答案
使用 Moq参考Mock HttpClient
假设你有一个控制器
[Route("api/[controller]")]
public class ValuesController : Controller {
private readonly IHttpClientFactory _httpClientFactory;
public ValuesController(IHttpClientFactory httpClientFactory) {
_httpClientFactory = httpClientFactory;
}
[HttpGet]
public async Task<IActionResult> Get() {
var client = _httpClientFactory.CreateClient();
var url = "http://example.com";
var result = await client.GetStringAsync(url);
return Ok(result);
}
}
并想测试Get()
动作。
public async Task Should_Return_Ok() {
//Arrange
var expected = "Hello World";
var mockFactory = new Mock<IHttpClientFactory>();
var configuration = new HttpConfiguration();
var clientHandlerStub = new DelegatingHandlerStub((request, cancellationToken) => {
request.SetConfiguration(configuration);
var response = request.CreateResponse(HttpStatusCode.OK, expected);
return Task.FromResult(response);
});
var client = new HttpClient(clientHandlerStub);
mockFactory.Setup(_ => _.CreateClient(It.IsAny<string>())).Returns(client);
IHttpClientFactory factory = mockFactory.Object;
var controller = new ValuesController(factory);
//Act
var result = await controller.Get();
//Assert
result.Should().NotBeNull();
var okResult = result as OkObjectResult;
var actual = (string) okResult.Value;
actual.Should().Be(expected);
}
推荐阅读
- rxjs - Rxjs - 在订阅函数中等待
- ios - 没有找到 `React-fishhook` 的 podspec
- css - 在 Angular UI-Grid 中选择一行时复制剪贴板上的行数据
- java - 在多个登录的 Web 用户之间分隔变量的值
- symfony - 如何在 Symfony 中将服务注入工厂创建的对象
- laravel - 如何从嵌套查询中添加连接列
- c# - 在控制器内抛出异常时停止重试
- jenkins - 从下游作业获取内部版本号
- php - 我如何仅使用 php 和 mysql 数据库在周六网页中查看员工的周日生日
- c++ - 亚马逊示例 transfermanager 代码无法编译