我很难用
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 调用的正确方法是什么?
我想您正在使用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);
测试我的功能而不进行真正的 HTTP 调用的正确方法是什么?
也许不是您想要的,但我建议您考虑 Andrew Lock 的智慧 - 不要在 ASP.NET Core 中对 API/MVC 控制器进行单元测试。
对于 .NET Core(和 .NET 5),如果您正在测试控制器类,则应该避免模拟 HttpClient。
如果控制器类不是您的 SUT,我会将 HttpClient 包装在外观接口中并模拟它。