我正在尝试为HttpClient服务编写一些单元测试,并且在尝试模拟GetAccessToken()函数中的部分代码时遇到问题。
该服务接受一个IHttpClientFactory。从到目前为止的阅读看来,要正确地模拟它,我必须模拟IHttpClientFactory,让它返回依赖于模拟的HttpMessageHandler的新HttpClient,我这样做是这样的:
var mockHttpClientFactory = new Mock<IHttpClientFactory>();
var mockHttpMessageHandler = new Mock<HttpMessageHandler>();
mockHttpMessageHandler.Protected()
.Setup<Task<HttpResponseMessage>>("SendAsync", ItExpr.IsAny<HttpRequestMessage>(), ItExpr.IsAny<CancellationToken>())
.ReturnsAsync(new HttpResponseMessage
{
StatusCode = HttpStatusCode.OK,
Content = new StringContent("{'name':thecodebuzz,'city':'USA'}"),
});
var client = new HttpClient(mockHttpMessageHandler.Object);
mockHttpClientFactory.Setup(x => x.CreateClient(It.IsAny<string>())).Returns(client);
_httpClientService = new HttpClientService(mockHttpClientFactory.Object, mockConfig.Object);
此方面有效,我已经能够调用运行正常的CreateClient()了。但是,我要测试的函数调用了我的GetAccessToken()函数,该函数又调用了client.GetDiscoveryAccessToken()。我猜想GetDiscoveryAccessToken()函数需要被模拟,但是我不确定如何继续。
我尝试用模拟方法创建客户端模拟,并在像这样调用CreateClient时返回此模拟:
var discoDoc = // Mocked disco doc code;
var client = new Mock<HttpClient>(mockHttpMessageHandler.Object);
client.Setup(x => x.GetDiscoveryDocumentAsync(It.IsAny<string>())).Returns(discoDoc);
mockHttpClientFactory.Setup(x => x.CreateClient(It.IsAny<string>())).Returns(client);
_httpClientService = new HttpClientService(mockHttpClientFactory.Object, mockConfig.Object);
[不幸的是,我收到此错误:“无法从'Moq.Mock'转换为'System.Net.Http.HttpClient'”,我告诉CreateClient函数返回什么。我猜这是因为我需要返回一个真正的HttpClient而不是模拟的。
关于我可以从这里去哪里的任何想法?
您几乎在那里,对于CreateClient,您将返回Moq的对象,而不是模拟的对象。只需返回如下所示的模拟对象即可。
var discoDoc = // Mocked disco doc code;
var client = new Mock<HttpClient>(mockHttpMessageHandler.Object);
client.Setup(x => x.GetDiscoveryDocumentAsync(It.IsAny<string>())).Returns(discoDoc);
mockHttpClientFactory.Setup(x => x.CreateClient(It.IsAny<string>())).Returns(client.Object);
_httpClientService = new HttpClientService(mockHttpClientFactory.Object, mockConfig.Object);
让我知道这是否是您所期望的。