单元测试 | 如何Mock IHttpClientFactory

前言

编写单元测试时,常常需要使用Mock框架(例如Moq)生成测试类的依赖接口的"模拟"实现,并验证接口是否按预期使用:

_mediatorMock = new Mock<IMediator>();

_mediatorMock.Setup(x => x.Send(It.IsAny<IdentifiedCommand<CancelOrderCommand, bool>>(), default(CancellationToken)))
    .Returns(Task.FromResult(true));

但是,对于IHttpClientFactory就不仅仅是Mock<IHttpClientFactory>这么简单了!

问题

因为,在实现代码中,我们并不是直接使用IHttpClientFactory对象,而是IHttpClientFactory对象使用CreateClient方法生成的HttpClient实例,而且我们也不希望真正的执行HTTP调用。

因此,我们需要Mock这种依赖性,并处理HttpClient实例的调用返回。

实现

IHttpClientFactory的Mock代码非常简单:

var httpClient = new HttpClient(handlerMock.Object) { 
        BaseAddress = new Uri("https://www.baidu.com/") 
    };

var mockHttpClientFactory = new Mock<IHttpClientFactory>();

mockHttpClientFactory.Setup(x => x.CreateClient("Baidu")).Returns(httpClient);

关键点在于,HttpClient构造函数传入的Mock对象handlerMock,它是用于实现发送请求的HTTP处理程序:

HttpResponseMessage result = new HttpResponseMessage();

handlerMock
    .Protected()
    .Setup<Task<HttpResponseMessage>>(
        "SendAsync",
        It.IsAny<HttpRequestMessage>(),
        It.IsAny<CancellationToken>()
    )
    .ReturnsAsync(result)

由于HttpMessageHandler的SendAsync方法可访问性级别是protected,因此需要使用.Protected()进行设置:

5eead2cdf7e4b7d51ff3ac2241f5130e.png

我们可以修改It.IsAny(),以匹配实际的请求。比如:

It.Is<HttpRequestMessage>(req => 
    req.RequestUri.Query.Contains("My%20IO")
)

现在,我们就可以在单元测试中正常使用IHttpClientFactory了

service = new DemoService(mockHttpClientFactory.Object);

结论

在本文中,我们实现了Mock IHttpClientFactory。

如果你觉得这篇文章对你有所启发,请关注我的个人公众号”My IO“

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值