代码之家  ›  专栏  ›  技术社区  ›  Praveen

单元测试动作过滤器-如何模拟ViewResult

  •  6
  • Praveen  · 技术社区  · 14 年前

    我在SO上搜索了一下,看起来这个问题经常被问到。我已经能够让mock工作了,而且我还能够执行OnActionExecuted(),没有任何问题。这是我的单元测试。注释行是失败的,我肯定我没有嘲笑正确的类型。

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

    这是我的动作过滤器。

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

    非常感谢!

    1 回复  |  直到 14 年前
        1
  •  9
  •   Darin Dimitrov    14 年前

    首先,让我们从修复操作过滤器开始,因为当前代码看起来很糟糕,而这些铸件可能会给您带来麻烦:

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

    以及单元测试:

    // 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
    

    备注:您的操作筛选器对 WrapperFactory 班级。这不好。进一步的改进是将此功能抽象到一个接口中,该接口将被注入到动作过滤器的构造函数中。这将允许您在应用程序的不同层之间进一步分离关注点。