如何进行单元测试以在 ASP.NET MVC 中使用路由?
我正在针对 ASP.NET MVC 应用程序编写单元测试,特别是正在测试我编写的 HtmlHelper 扩展方法。扩展方法内部有一行:
var innerHtml = htmlHelper.ActionLink(text, action, controller, routeValues, null);
当我在单元测试内部运行此行时,无论传入的操作或控制器如何,生成的 URL 的 href 都是空白。
这是我的单元测试:
var page = CreateProductDataPage(); //returns ProductDataPage object
var htmlHelper = Http.CreateHtmlHelperWithMocks<ProductDataPage>(new ViewDataDictionary<ProductDataPage>(page), false);
var result = htmlHelper.ProductListingBreadcrumb(true, null, null);
这是 CreateHtmlHelperWithMocks 方法:
public static HtmlHelper<T> CreateHtmlHelperWithMocks<T>(ViewDataDictionary<T> viewData, bool isLoggedIn) where T : class
{
var mockViewDataContainer = new Mock<IViewDataContainer>();
mockViewDataContainer.SetupGet(v => v.ViewData).Returns(viewData);
return new HtmlHelper<T>(GetViewContextMock(viewData, isLoggedIn).Object, mockViewDataContainer.Object);
}
最后,这是 GetViewContextMock 方法:
public static Mock<ViewContext> GetViewContextMock(ViewDataDictionary viewData, bool isLoggedIn)
{
var mock = new Mock<ViewContext>();
mock.SetupGet(v => v.HttpContext).Returns(GetHttpContextMock(isLoggedIn).Object);
mock.SetupGet(v => v.Controller).Returns(new Mock<ControllerBase>().Object);
mock.SetupGet(v => v.View).Returns(new Mock<IView>().Object);
mock.SetupGet(v => v.ViewData).Returns(viewData);
mock.SetupGet(v => v.TempData).Returns(new TempDataDictionary());
mock.SetupGet(v => v.RouteData).Returns(new RouteData());
return mock;
}
I am writing unit tests against my ASP.NET MVC application, in particular I am testing an HtmlHelper extension method that I wrote. There is a line inside of the extension method:
var innerHtml = htmlHelper.ActionLink(text, action, controller, routeValues, null);
When I run this inside of my unit test, the href of the generated URL is blank regardless of the action or controller passed in.
Here is my unit test:
var page = CreateProductDataPage(); //returns ProductDataPage object
var htmlHelper = Http.CreateHtmlHelperWithMocks<ProductDataPage>(new ViewDataDictionary<ProductDataPage>(page), false);
var result = htmlHelper.ProductListingBreadcrumb(true, null, null);
Here is the CreateHtmlHelperWithMocks method:
public static HtmlHelper<T> CreateHtmlHelperWithMocks<T>(ViewDataDictionary<T> viewData, bool isLoggedIn) where T : class
{
var mockViewDataContainer = new Mock<IViewDataContainer>();
mockViewDataContainer.SetupGet(v => v.ViewData).Returns(viewData);
return new HtmlHelper<T>(GetViewContextMock(viewData, isLoggedIn).Object, mockViewDataContainer.Object);
}
Finally, here is the GetViewContextMock method:
public static Mock<ViewContext> GetViewContextMock(ViewDataDictionary viewData, bool isLoggedIn)
{
var mock = new Mock<ViewContext>();
mock.SetupGet(v => v.HttpContext).Returns(GetHttpContextMock(isLoggedIn).Object);
mock.SetupGet(v => v.Controller).Returns(new Mock<ControllerBase>().Object);
mock.SetupGet(v => v.View).Returns(new Mock<IView>().Object);
mock.SetupGet(v => v.ViewData).Returns(viewData);
mock.SetupGet(v => v.TempData).Returns(new TempDataDictionary());
mock.SetupGet(v => v.RouteData).Returns(new RouteData());
return mock;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
更新:弄清楚了。 a$$ 真是太痛苦了。万一其他人尝试这样做...
第一步是在创建模拟 HtmlHelper 时添加来自 global.asax 的路线集合。
然后,我必须确保 HttpContext 模拟为请求的 ApplicationPath 属性和响应的 ApplyAppPathModifier 方法返回结果。
Update: Figured it out. What a pain in the a$$. In case anyone else tries to do this...
The first step was to add the Route Collection from the global.asax in the creation of the mock HtmlHelper.
Then I had to make sure the HttpContext mock had a result being returned for the Request's ApplicationPath property and the Response's ApplyAppPathModifier method.
大约一个月前,我在博客中介绍了如何使用 Rhino.Mocks 进行此操作。您可以在 http://farm-fresh-code.blogspot.com/2009/10/mocking-htmlhelper-class-with.html。基本上,我的解决方案是在模拟中提供所有内容,包括在 RouteData 中以及通过连接到模拟助手的 Response 对象上的 ApplyAppPathModifier。它实际上更像是一个基于底层存根的假助手。
I blogged about doing this with Rhino.Mocks about a month ago. You can find more information on how I handle this at http://farm-fresh-code.blogspot.com/2009/10/mocking-htmlhelper-class-with.html. Basically, my solution is to provide everything in the mock, both in the RouteData and via the ApplyAppPathModifier on the Response object connected to the mock helper. It's actually more of a fake helper based on underlying stubs.