2010-10-01 9 views
6

Hice una búsqueda en SO y parece que esta pregunta se hace con bastante frecuencia. Pude hacer funcionar los simulacros y también puedo ejecutar OnActionExecuted() sin problemas. Aquí está mi Prueba de Unidad. Las líneas comentadas son las que fallan y estoy seguro de que no me estoy burlando del tipo correcto.Filtros de acción de prueba de la unidad - Cómo imitar ViewResult

 //Arrange 
     //var viewResult = new ViewResult(); 
     var filterContextMock = new Mock<ActionExecutedContext>(); 
     var routeData = new RouteData(); 
     var httpContextMock = new Mock<HttpContextBase>(); 

     routeData.Values["data"] = "Mock data"; 
     var requestContext = new RequestContext(httpContextMock.Object, routeData); 

     var controller = new FakeController(); 
     controller.ControllerContext = new ControllerContext(requestContext, controller); 

     filterContextMock.Setup(f => f.RouteData).Returns(routeData); 
     filterContextMock.Setup(f => f.Controller).Returns(controller); 
     //filterContextMock.Setup(f => f.Result).Returns(viewResult); 

     //Act 
     var wrapFilterAttribute = new WrapFilterAttribute(); 
     wrapFilterAttribute.OnActionExecuted(filterContextMock.Object); 

Aquí está mi filtro de acción.

public class WrapFilterAttribute : ActionFilterAttribute 
{ 
    public override void OnActionExecuted(ActionExecutedContext filterContext) 
    { 
     var view = (ViewResultBase)filterContext.Result; 

     if (view != null) 
     { 
      BaseViewModel viewModel = (BaseViewModel)view.ViewData.Model ?? new BaseViewModel(); 
      viewModel.Wrap = new WrapperFactory().GetWrap(); 
     } 

     base.OnActionExecuted(filterContext); 
    } 
} 

El problema al que me enfrento aquí es filterContext.Result siempre aparece como EmptyResult. Me gustaría empujar en su lugar un ViewResult hidratado. ¿Alguna idea de cómo puedo lograr esto?

¡Muchas gracias!

Respuesta

9

En primer lugar vamos a empezar por la fijación de su filtro de acción ya que actualmente el código se ve mal y esas piezas fundidas que podría traer dolores de cabeza:

public class WrapFilterAttribute : ActionFilterAttribute 
{ 
    public override void OnActionExecuted(ActionExecutedContext filterContext) 
    { 
     var view = filterContext.Result as ViewResultBase; 
     if (view != null) 
     { 
      // the controller action returned a ViewResultBase 
      var viewModel = view.ViewData.Model as BaseViewModel; 
      if (viewModel != null) 
      { 
       // the model passed to the view was derived from 
       // BaseViewModel so we can safely update the Wrap 
       // property 
       viewModel.Wrap = new WrapperFactory().GetWrap(); 
      } 
     } 
     base.OnActionExecuted(filterContext); 
    } 
} 

y la prueba de unidad:

// arrange 
var sut = new WrapFilterAttribute(); 
var filterContextMock = new Mock<ActionExecutedContext>(); 
var viewResultMock = new Mock<ViewResultBase>(); 
filterContextMock.Object.Result = viewResultMock.Object; 
var viewModel = new BaseViewModel(); 
viewResultMock.Object.ViewData.Model = viewModel; 

// act 
sut.OnActionExecuted(filterContextMock.Object); 

// assert 
// TODO: assert something on the viewModel.Wrap property like 
// for example that it has been initialized 

Observación: el filtro de la acción tiene una fuerte dependencia en la clase WrapperFactory. Esto no está bien. Una mejora adicional sería abstraer esta funcionalidad en una interfaz que se inyectaría en el constructor del filtro de acción. Esto le permitiría una mayor separación de preocupaciones entre las diferentes capas de su aplicación.

+0

Gracias por refactorizar mi código de mierda Darin. Esto funcionó para mí. Gracias de nuevo :) – Praveen

+0

Tu comentario sobre la inyección de WrapperFactory en el constructor del filtro de acción me da curiosidad. ¿Cómo lograría enviar una instancia de WrapperFactory a través de la decoración WrapFilterAttribute? AFAIK, los atributos requieren valores de tiempo de compilación (constantes, etc.). – Praveen

+1

@Praveen, aquí hay un ejemplo de cómo lograr [inyección de constructor con filtros de acción] (http://iridescence.no/post/Constructor-Injection-for-ASPNET-MVC-Action-Filters.aspx). Es un poco raro, pero esa es la única manera por el momento. Esto se ha mejorado en ASP.NET MVC 3. –