存根或模拟 ASP.NET Web API HttpClient
本文关键字:Web API HttpClient NET ASP 模拟 存根 | 更新日期: 2023-09-27 18:34:57
我在项目中使用新的Web API位,并且发现我无法使用正常的HttpMessageRequest
,因为我需要将客户端证书添加到请求中。结果,我正在使用HttpClient
(所以我可以使用WebRequestHandler
(。这一切都运行良好,除了它对存根/模拟不友好,至少对于 Rhino Mocks 来说是这样。
我通常会围绕HttpClient
创建一个包装器服务,但如果可能的话,我想避免这种情况,因为我需要包装很多方法。我希望我错过了一些东西——关于如何存根HttpClient
的任何建议?
作为@Raj已经提出的优秀想法的替代方案,也许可以降低一步,而是模拟/伪造HttpMessageHandler
。
如果您创建任何需要HttpClient
的类接受它作为构造函数中的依赖项注入参数,那么在单元测试时,您可以传入已注入您自己的HttpMessageHandler
的HttpClient
。这个简单的类只有一个需要实现的抽象方法,如下所示:
public class FakeHttpMessageHandler : HttpMessageHandler
{
public HttpRequestMessage RequestMessage { get; private set; }
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
RequestMessage = request;
return Task.FromResult(new HttpResponseMessage(HttpStatusCode.OK));
}
}
我的简单示例只是将HttpRequestMessage
保存在公共属性中以供以后检查并返回 HTTP 200(OK(,但您可以通过添加一个设置要返回的结果的构造函数来增强这一点。
你可以像这样使用这个类:
public void foo()
{
//Arrange
var fakeHandler = new FakeHttpMessageHandler();
var client = new HttpClient(fakeHandler);
var SUT = new ClassUnderTest(client);
//Act
SUT.DomSomething();
//Assert
fakeHandler.RequestMessage.Method.ShouldEqual(HttpMethod.Get); // etc...
}
这种方法存在局限性,例如,在发出多个请求或需要创建多个HttpClient
的方法中,假处理程序可能会开始变得过于复杂。但是,对于简单的情况,可能值得考虑。
前我发布了一个名为MockHttp的库,它可能很有用。它使用具有流畅(且可扩展(API 的自定义HttpMessageHandler
。您可以将模拟处理程序(或 HttpClient(注入到服务类中,它将在配置时响应。
下面显示了基本用法。When
和 Respond
方法具有一堆重载,包括运行自定义逻辑。GitHub 页面上的文档详细介绍了更多内容。
var mockHttp = new MockHttpMessageHandler();
// Setup a respond for the user api (including a wildcard in the URL)
mockHttp.When("http://localhost/api/user/*")
.Respond("application/json", "{'name' : 'Test McGee'}"); // Respond with JSON
// Inject the handler or client into your application code
var client = new HttpClient(mockHttp);
var response = async client.GetAsync("http://localhost/api/user/1234");
// or without async: var response = client.GetAsync(...).Result;
var json = await response.Content.ReadAsStringAsync();
// No network connection required
Console.Write(json); // {'name' : 'Test McGee'}
我使用最小起订量,我可以存根HttpClient。我认为犀牛嘲笑也是如此(我自己还没有尝试过(。如果你只想存根HttpClient,下面的代码应该可以工作:
var stubHttpClient = new Mock<HttpClient>();
ValuesController controller = new ValuesController(stubHttpClient.Object);
如果我错了,请纠正我。我猜你指的是在 HttpClient 中剔除成员。
最流行的隔离/模拟对象框架不允许你在非虚拟成员上存根/设置例如,下面的代码引发异常
stubHttpClient.Setup(x => x.BaseAddress).Returns(new Uri("some_uri");
您还提到您希望避免创建包装器,因为您将包装大量 HttpClient 成员。不清楚为什么需要包装大量方法,但您可以轻松地仅包装所需的方法。
例如:
public interface IHttpClientWrapper { Uri BaseAddress { get; } }
public class HttpClientWrapper : IHttpClientWrapper
{
readonly HttpClient client;
public HttpClientWrapper() {
client = new HttpClient();
}
public Uri BaseAddress {
get
{
return client.BaseAddress;
}
}
}
我认为可能对您有益的其他选项(有很多示例,所以我不会编写代码(Microsoft痣框架http://research.microsoft.com/en-us/projects/moles/Microsoft 假货:(如果您使用的是VS2012旗舰版(http://msdn.microsoft.com/en-us/library/hh549175.aspx