tag route net mvc data asp all .net asp.net-mvc unit-testing html-helper

route - Probando HtmlHelpers en ASP.NET MVC



tag helpers asp net core (3)

¿Hay alguna forma de (unidad) probar mis propios HtmlHelpers? En caso de que me gustaría tener un control personalizado (representado por HtmlHelper) y conozco los requisitos para ese control, ¿cómo podría escribir pruebas primero y luego escribir el código? ¿Hay alguna manera específica (agradable) de hacer eso?

¿Vale la pena?


Estoy creando un helper personalizado, y este es el código que estoy usando para simular el httphelper con Moq y ASP MVC 2. También estoy pasando como parámetro un simulacro de HttpRequestBase. Puedes eliminar eso si no lo necesitas

public static HtmlHelper CreateHtmlHelper(ViewDataDictionary viewData, Mock requestMock) { var contextBaseMock = new Mock(); contextBaseMock.SetupGet(cb => cb.Request).Returns(requestMock.Object); var cc = new ControllerContext(contextBaseMock.Object, new RouteData(), new Mock().Object); var vctx = new ViewContext( cc, new Mock().Object, viewData, new TempDataDictionary(), new HtmlTextWriter(new StreamWriter(new MemoryStream()))); var mockViewDataContainer = new Mock(); mockViewDataContainer.SetupGet(v => v.ViewData).Returns(viewData); return new HtmlHelper(vctx, mockViewDataContainer.Object); }


El principal problema es que tiene que burlarse del HtmlHelper porque puede estar utilizando métodos del helper para obtener rutas o valores o devolver el resultado de otro método de extensión. La clase HtmlHelper tiene bastantes propiedades y algunas bastante complejas como ViewContext o el Controlador actual.

Esta publicación de Ben Hart que explica cómo crear un simulacro con Moq. Se puede traducir fácilmente a otro marco simulado.

Esta es mi versión de Rhino Mocks adaptada a los cambios en el Marco MVC. No está completamente probado pero funciona para mí, pero no esperes resultados perfectos:

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); }


Si alguien está buscando cómo crear HtmlHelper<T> (eso es lo que buscaba), aquí hay una implementación que podría ayudar: mi tipo es una clase llamada Modelo:

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); }

O una implementación más genérica:

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); }