ASP.NET Core 模拟 HttpClient 与自定义 HttpClientHandler

问题描述 投票:0回答:2

我很难用

Moq
来嘲笑。 通常有一个
HttpClient
我会通过在基类中注入
HttpClient
来模拟它,如下所示:

public class MyClass
{
    private readonly HttpClient httpClient;

    public MyClass(HttpClient httpClient)
    {
        this.httpClient = httpClient;
    }
}

但现在我的班级有不同的功能

MyClass
,需要自定义
HttpClientHandler
,如下所示:

HttpClientHandler httpClientHandler = new HttpClientHandler();
...
using var client = new HttpClient(httpClientHandler);

如果我只是用

HttpClient
MyClassTest
中注入
var service = new MyClass(httpMock.Object);
,那么 httpClient 将被覆盖。

测试我的功能而不进行真正的 HTTP 调用的正确方法是什么?

c# unit-testing asp.net-core moq dotnet-httpclient
2个回答
1
投票

我想您正在使用IHttpClientFactory

类型化客户端
方法。这就是为什么你的
MyClass
ctor 会收到
HttpClient
实例。

如果您需要嘲笑它

HttpClient
那么我建议您遵循Hamid Mosalla的建议

简而言之,有一个帮助器类,它使

HttpMessageHandler
SendAsync
可模拟(无需使用 Moq.Protected)。

public class FakeHandler: HttpMessageHandler
{
    public virtual HttpResponseMessage Send(HttpRequestMessage request)
    {
        throw new NotImplementedException();
    }

    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        return Task.FromResult(Send(request));
    }
}

您可以像这样使用这个帮助器类来模拟任何

HttpClient
调用:

var httpResponse = new HttpResponseMessage
{
    Content = new StringContent(JsonConvert.SerializeObject(responseObject))
};

var mockHandler = new Mock<FakeHandler> { CallBase = true };
mockHandler
    .Setup(handler => handler.Send(It.IsAny<HttpRequestMessage>()))
    .Returns(httpResponse);

var mockHttpClient = new HttpClient(mockHandler.Object);
var SUT = new MyClass(mockHttpClient);

1
投票

测试我的功能而不进行真正的 HTTP 调用的正确方法是什么?

也许不是您想要的,但我建议您考虑 Andrew Lock 的智慧 - 不要在 ASP.NET Core 中对 API/MVC 控制器进行单元测试

对于 .NET Core(和 .NET 5),如果您正在测试控制器类,则应该避免模拟 HttpClient。

如果控制器类不是您的 SUT,我会将 HttpClient 包装在外观接口中并模拟它。

© www.soinside.com 2019 - 2024. All rights reserved.