首页 > 解决方案 > 如何使用 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);

标签: c#unit-testingmoqasp.net-core-2.1httpclientfactory

解决方案


HttpClientFactory是从IHttpClientFactoryInterface派生的所以只需要创建一个接口的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);
}

推荐阅读