【发布时间】:2010-09-21 06:21:13
【问题描述】:
有没有办法(单元)测试我自己的 HtmlHelpers?如果我想要自定义控件(由 HtmlHelper 呈现)并且我知道该控件的要求,我该如何先编写测试 - 然后编写代码?有没有特定的(好的)方法可以做到这一点?
值得吗?
【问题讨论】:
标签: .net asp.net-mvc unit-testing html-helper
有没有办法(单元)测试我自己的 HtmlHelpers?如果我想要自定义控件(由 HtmlHelper 呈现)并且我知道该控件的要求,我该如何先编写测试 - 然后编写代码?有没有特定的(好的)方法可以做到这一点?
值得吗?
【问题讨论】:
标签: .net asp.net-mvc unit-testing html-helper
主要问题是您必须模拟 HtmlHelper,因为您可能正在使用帮助程序的方法来获取路由或值或返回另一个扩展方法的结果。 HtmlHelper 类有很多属性,其中一些非常复杂,例如 ViewContext 或当前的 Controller。
This post from Ben Hart 解释了如何使用 Moq 创建这样的模拟。可以轻松转换为另一个模拟框架。
这是我的 Rhino Mocks 版本适应了 MVC 框架的变化。它尚未经过全面测试,但对我有用,但不要指望完美的结果:
public static HtmlHelper CreateHtmlHelper(ViewDataDictionary viewData)
{
var mocks = new MockRepository();
var cc = mocks.DynamicMock<ControllerContext>(
mocks.DynamicMock<HttpContextBase>(),
new RouteData(),
mocks.DynamicMock<ControllerBase>());
var mockViewContext = mocks.DynamicMock<ViewContext>(
cc,
mocks.DynamicMock<IView>(),
viewData,
new TempDataDictionary());
var mockViewDataContainer = mocks.DynamicMock<IViewDataContainer>();
mockViewDataContainer.Expect(v => v.ViewData).Return(viewData);
return new HtmlHelper(mockViewContext, mockViewDataContainer);
}
【讨论】:
TextWriter.Null)来调整它,而不是 mockViewDataContainer,我必须显式设置 ViewData(例如,mockViewDataContainer.ViewData = viewData;) 或 Rhino Mocks 会抛出异常。
如果有人正在寻找如何创建 HtmlHelper<T>(这就是我所追求的),这里有一个可能会有所帮助的实现 - 我的类型是一个名为 Model 的类:
public static HtmlHelper<Model> CreateHtmlHelper()
{
ViewDataDictionary vd = new ViewDataDictionary(new Model());
var controllerContext = new ControllerContext(new Mock<HttpContextBase>().Object,
new RouteData(),
new Mock<ControllerBase>().Object);
var viewContext = new ViewContext(controllerContext, new Mock<IView>().Object, vd, new TempDataDictionary(), new Mock<TextWriter>().Object);
var mockViewDataContainer = new Mock<IViewDataContainer>();
mockViewDataContainer.Setup(v => v.ViewData).Returns(vd);
return new HtmlHelper<Model>(viewContext, mockViewDataContainer.Object);
}
或者更通用的实现:
public HtmlHelper<T> CreateHtmlHelper<T>() where T : new()
{
var vd = new ViewDataDictionary(new T());
var controllerContext = new ControllerContext(new Mock<HttpContextBase>().Object,
new RouteData(),
new Mock<ControllerBase>().Object);
var viewContext = new ViewContext(controllerContext, new Mock<IView>().Object, vd, new TempDataDictionary(), new Mock<TextWriter>().Object);
var mockViewDataContainer = new Mock<IViewDataContainer>();
mockViewDataContainer.Setup(v => v.ViewData).Returns(vd);
return new HtmlHelper<T>(viewContext, mockViewDataContainer.Object);
}
【讨论】:
我正在创建一个自定义助手,这是我用来模拟带有 Moq 和 ASP MVC 2 的 httphelper 的代码。我还将作为参数传递一个 HttpRequestBase 的模拟。如果你不需要它,你可以删除它
公共静态 HtmlHelper CreateHtmlHelper(ViewDataDictionary viewData, Mock requestMock) { var contextBaseMock = new Mock(); contextBaseMock.SetupGet(cb => cb.Request).Returns(requestMock.Object); var cc = new ControllerContext(contextBaseMock.Object, 新的路线数据(), 新的 Mock().Object); var vctx = 新的 ViewContext( 抄送, 新的 Mock().Object, 视图数据, 新的 TempDataDictionary(), 新 HtmlTextWriter(新 StreamWriter(新 MemoryStream()))); var mockViewDataContainer = new Mock(); mockViewDataContainer.SetupGet(v => v.ViewData).Returns(viewData); 返回新的 HtmlHelper(vctx, mockViewDataContainer.Object); }【讨论】: