1

我正在尝试为 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);

不幸的是,我在告诉 CreateClient 函数返回什么的那一行出现了这个错误:“无法从 'Moq.Mock' 转换为 'System.Net.Http.HttpClient'”。我猜这是因为我需要返回一个真正的 HttpClient 而不是一个 Mocked 。

关于我可以从这里去哪里的任何想法?

4

2 回答 2

1

实际上没有办法嘲笑这一点。对此进行测试的唯一方法是以与 IdentityModel 团队类似的方式进行 - 使用他们自己的 HttpMessageHandler 实现。(NetworkHandler)然后您可以执行以下操作:

HttpResponseMessage GetDiscoveryResponse()
{
    var wellKnown = File.ReadAllText("openid-configuration.json");
    var response = new HttpResponseMessage(HttpStatusCode.OK)
    {
        Content = new StringContent(wellKnown)
    };
    return response;
};
var httpClient = new HttpClient(new NetworkHandler(request => {
    if (request.RequestUri.AbsoluteUri.Contains("openid-configuration"))
    {
        return GetDiscoveryResponse();
    }
    throw new NotImplementedException();
}));
于 2021-03-05T09:28:00.690 回答
1

您快到了,对于 CreateClient,您正在返回 Moq 的对象,而不是 Mocked 对象。只需要返回模拟对象,如下所示。

 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);

让我知道这是否是您所期望的。

于 2020-06-04T11:15:18.807 回答