c# - .NET MVC 中带有 HttpClient 的单元测试控制器
问题描述
所以我有一个控制器,它使用 HttpClient 来调用 web 服务,如下所示:
public class DemoController : Controller
{
HttpClient client;
string baseUrl = "http://localhost:90/webservice";
public DemoController()
{
client = new HttpClient
{
BaseAddress = new Uri(baseUrl)
};
}
// GET: DemoInfo
public async Task<ActionResult> Index()
{
HttpResponseMessage response = await client.GetAsync(baseUrl + "vehicle/menu/year");
string content = "";
MenuItems result = null;
if (response.IsSuccessStatusCode)
{
content = await response.Content.ReadAsStringAsync();
result = (MenuItems)new XmlSerializer(typeof(MenuItems)).Deserialize(new StringReader(content));
}
return View("Index", result);
}
}
我对此操作的单元测试如下:
[TestMethod]
public async Task Test_Index()
{
// Arrange
DemoController controller = new DemoController();
// Act
var result = await controller.Index();
ViewResult viewResult = (ViewResult) result;
// Assert
Assert.AreEqual("Index", viewResult.ViewName);
Assert.IsNotNull(viewResult.Model);
}
所以显然我想避免每次运行测试时都调用 Web 服务。在选择像 Unity 这样的 IoC 容器以便将 HttpClient 注入控制器时,我会走上正确的道路吗?这对我想要达到的目标来说是不是有点矫枉过正?我知道有很多人在通过这个github 问题在单元测试中正确地模拟 httpclient 的历史。任何帮助都将非常感谢您深入了解如何编写控制器以在仍可测试的同时进行服务调用。
解决方案
在没有服务包装器、模拟或 IoC 容器的情况下测试HttpClient
调用的另一种方法是使用FlurlHttpClient
,这是一个围绕它提供(除其他外)一些强大的测试功能的小型包装器库。[免责声明:我是作者]
这是您的控制器的外观。有几种方法可以做到这一点,但这种方法使用完全抽象出客户端的字符串扩展方法。HttpClient
(为您管理每个主机的单个实例以防止麻烦。)
using Flurl.Http;
public class DemoController : Controller
{
string baseUrl = "http://localhost:90/webservice";
// GET: DemoInfo
public async Task<ActionResult> Index()
{
var content = await baseUrl
.AppendPathSegment("vehicle/menu/year")
.GetStringAsync();
var result = (MenuItems)new XmlSerializer(typeof(MenuItems)).Deserialize(new StringReader(content));
return View("Index", result);
}
}
和测试:
using Flurl.Http;
[TestMethod]
public async Task Test_Index()
{
// fake & record all HTTP calls in the test subject
using (var httpTest = new HttpTest())
{
// Arrange
httpTest.RespondWith(200, "<xml>some fake response xml...</xml>");
DemoController controller = new DemoController();
// Act
var result = await controller.Index();
ViewResult viewResult = (ViewResult) result;
// Assert
Assert.AreEqual("Index", viewResult.ViewName);
Assert.IsNotNull(viewResult.Model);
}
}
Flurl.Http 在NuGet上可用。
推荐阅读
- node.js - 如何从节点接收 JSON 对象并在客户端显示它?
- html - 我怎样才能让这个布局像它应该的那样对齐?
- excel - MS Access 在几分钟内写入 Excel 有时会引发错误错误
- amazon-web-services - 缓存和 SignedURL 之间的冲突(将内容设为私有)
- flutter - Dart 或 Flutter - 哪个先?
- excel - 将 If/End If 添加到宏
- java - 在电池电量不足时禁用关机
- python - 如何解码 url 中的数字
- jquery - 将 pdf 添加到 FancyBox 画廊
- javascript - 有人可以帮我用javascript写这个吗