How To Write Unit Test For Method Returning JsonResult With RenderPartialViewToString?

巧了我就是萌 提交于 2019-12-20 10:57:23

问题


If you look at the example at this link:

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

How would one write a unit test for the JsonAdd method? I have a similar situation in my own code, but the RenderPartialViewToString errors when calling:

ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView

I've tried different ways of trying to stub that call to no avail. Any help appreciated. Thanks.


回答1:


Since ViewEninges is a static class, you can't mock it with RhinoMocks. I think your best bet is to create a "partial view renderer" interface. An interface is mockable so you'll be able to stub out the complexity of rendering the view. Here's some quick pseudo-code thrown together.

First, define the partial view renderer interface:

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

Then, change your base class' RenderPartialViewToString to be the implementation of IRenderPartialView.Render:

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

Now we need to change your controller constructors so we can inject an IRenderPartialView during testing -- but use the base class one during production. We can accomplish this by using a pair of constructors:

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

Now, JsonAdd can call the partial view renderer:

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

So, during testing, you'll mock out an IRenderPartialView and send that to the constructor that accepts an IRenderPartialView. During production, when ASP.NET MVC calls your default constructor, it will use the controller as the renderer (which has the implementation of IRenderPartialView.Render inside the base class).




回答2:


I had a lot of trouble to make unit test working with RenderPartialViewToString. I succeeded by doing 2 things. I had to mock the view engine and the controller context.

Here the code :

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

And that is the way i use it all :

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

Here are my sources : View engine mocking : http://thoai-nguyen.blogspot.fr/2011/04/test-mock-mvc-view-engine.html

Controller context mocking : ASP.NET MVC - Unit testing RenderPartialViewToString() with Moq framework?

Hope this help.



来源:https://stackoverflow.com/questions/3462006/how-to-write-unit-test-for-method-returning-jsonresult-with-renderpartialviewtos

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!