【问题标题】:How To Write Unit Test For Method Returning JsonResult With RenderPartialViewToString?如何为使用 RenderPartialViewToString 返回 JsonResult 的方法编写单元测试?
【发布时间】:2011-03-28 13:57:18
【问题描述】:

如果您查看此链接中的示例:

http://www.atlanticbt.com/blog/asp-net-mvc-using-ajax-json-and-partialviews/

如何为 JsonAdd 方法编写单元测试?我自己的代码也有类似的情况,但是调用时出现 RenderPartialViewToString 错误:

ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView

我尝试了不同的方法来尝试存根该调用,但无济于事。任何帮助表示赞赏。谢谢。

【问题讨论】:

    标签: unit-testing model-view-controller rhino-mocks mvccontrib


    【解决方案1】:

    我在使用 RenderPartialViewToString 进行单元测试时遇到了很多麻烦。 我成功地做了两件事。 我不得不模拟视图引擎和控制器上下文。

    这里是代码:

    public ViewEngineResult SetupViewContent(string viewName, string viewHtmlContent)
        {
            var mockedViewEngine = new Mock<IViewEngine>();
            var resultView = new Mock<IView>();
    
            resultView.Setup(x => x.Render(It.IsAny<ViewContext>(), It.IsAny<TextWriter>()))
                .Callback<ViewContext, TextWriter>((v, t) =>
                {
                    t.Write(viewHtmlContent);
                });
    
            var viewEngineResult = new ViewEngineResult(resultView.Object, mockedViewEngine.Object);
            mockedViewEngine.Setup(x => x.FindPartialView(It.IsAny<ControllerContext>(), viewName, It.IsAny<bool>()))
                .Returns<ControllerContext, string, bool>((controller, view, useCache) =>
                {
                    return viewEngineResult;
                });
    
            mockedViewEngine.Setup(x => x.FindView(It.IsAny<ControllerContext>(), viewName, It.IsAny<string>(), It.IsAny<bool>()))
                .Returns<ControllerContext, string, string, bool>((controller, view, masterName, useCache) =>
                {
                    return viewEngineResult;
                });
    
            ViewEngines.Engines.Clear();
            ViewEngines.Engines.Add(mockedViewEngine.Object);
            return viewEngineResult;
        }
    
        public void SetContext(ref PointCollecteLivraisonController controller)
        {
            SetupViewContent("MyViewName", "TheViewContent");
    
            var httpContextBase = new Mock<HttpContextBase>();
            var httpRequestBase = new Mock<HttpRequestBase>();
            var response = new Mock<HttpResponseBase>();
            var session = new Mock<HttpSessionStateBase>();
            var routes = new RouteCollection();
            RouteConfigurator.RegisterRoutes(routes);
            var routeData = new RouteData();
            routeData.Values.Add("controller", "PointCollecteLivraison");
            routeData.Values.Add("action", "RechercheJson");
    
            httpContextBase.Setup(x => x.Response).Returns(response.Object);
            httpContextBase.Setup(x => x.Request).Returns(httpRequestBase.Object);
            httpContextBase.Setup(x => x.Session).Returns(session.Object);
            session.Setup(x => x["somesessionkey"]).Returns("value");
            httpRequestBase.Setup(x => x.Form).Returns(new NameValueCollection());
            controller.ControllerContext = new ControllerContext(httpContextBase.Object, routeData, controller);
            controller.Url = new UrlHelper(new RequestContext(controller.HttpContext, routeData), routes);
        }
    

    这就是我使用它的方式:

    PointCollecteLivraisonController controller = new PointCollecteLivraisonController();
    SetContext(ref controller);
    

    这是我的来源: 查看引擎模拟:http://thoai-nguyen.blogspot.fr/2011/04/test-mock-mvc-view-engine.html

    控制器上下文模拟:ASP.NET MVC - Unit testing RenderPartialViewToString() with Moq framework?

    希望对您有所帮助。

    【讨论】:

    • 非常出色的工作。对于每个对 RouteConfigurator 有问题的人。 RegisterRoutes 默认在 Global.asax.cs 中,是 MvcApplication 的一部分(默认) 感谢这段代码,它对我帮助很大。
    【解决方案2】:

    由于 ViewEninges 是一个静态类,你不能用 RhinoMocks 模拟它。我认为你最好的选择是创建一个“局部视图渲染器”界面。界面是可模拟的,因此您将能够消除渲染视图的复杂性。这是一些快速的伪代码。

    首先,定义局部视图渲染器接口:

    public interface IRenderPartialView
    {
        string Render(string viewName, object model);
    }
    

    然后,将基类的 RenderPartialViewToString 更改为 IRenderPartialView.Render 的实现:

    public abstract class BaseController : Controller, IRenderPartialView
    {
    ...
        public string Render(string viewName, object model)
        {
            // same code as RenderPartialViewToString
        }
    }
    

    现在我们需要更改您的控制器构造函数,以便我们可以在测试期间注入 IRenderPartialView - 但在生产期间使用基类之一。我们可以通过使用一对构造函数来实现这一点:

    public class YourController : BaseController
    {
            private IRenderPartialView partialRenderer;
    
            public YourController()
            {
                SetRenderer(this);
            }
    
            public YourController(IRenderPartialView partialRenderer)
            {
                SetRenderer(partialRenderer);
            }
    
            private void SetRenderer(IRenderPartialView partialRenderer)
            {
                this.partialRenderer = this;
            }
    }
    

    现在,JsonAdd 可以调用局部视图渲染器了:

    public JsonResult JsonAdd(AddPersonViewModel AddPersonModel)
    {
        ...
        return Json(new
        {
            Success = true,
            Message = "The person has been added!",
            PartialViewHtml = partialRenderer.Render("PersonList", new PersonListViewModel {PersonList = _personList})
        });
    }
    

    因此,在测试期间,您将模拟出 IRenderPartialView 并将其发送给接受 IRenderPartialView 的构造函数。在生产过程中,当 ASP.NET MVC 调用你的默认构造函数时,它将使用控制器作为渲染器(在基类中实现了IRenderPartialView.Render)。

    【讨论】:

    • 我正在隔离对接口的依赖,但还没有完全理解多构造函数的想法。效果很好......谢谢帕特里克!
    猜你喜欢
    • 2011-06-26
    • 2022-01-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-06-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多