Looking for direction on unit testing a controller extension that renders a partial view
Asked Answered
Z

1

13

As the title says, I'm looking for direction on how to properly test a controller extension. The extension renders a partial view which in turn I'm using within a JSONResult:

 public static string RenderPartialViewToString(this Controller controller, string viewName = null, object model = null)
        {
            if (string.IsNullOrEmpty(viewName))
            {
                viewName = controller.ControllerContext.RouteData.GetRequiredString("action");
            }

            controller.ViewData.Model = model;

            using (StringWriter sw = new StringWriter())
            {
                ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(controller.ControllerContext, viewName);
                ViewContext viewContext = new ViewContext(controller.ControllerContext, viewResult.View, controller.ViewData, controller.TempData, sw);
                viewResult.View.Render(viewContext, sw);
                return sw.GetStringBuilder().ToString();
            }
        }

Example usage:

public JsonResult Foo()
{
    var model = _repository.getSomeData();

    return Json(new { html = this.RenderPartialViewToString("Index", model) }, JsonRequestBehavior.AllowGet);
}

I'm using NUnit & the MvcContrib test helper, however when setting up a controller that makes use of this extension I'm running into a NRE. I'm assuming that the controller context is not setup correctly?

Ultimately the test is barfing on ViewEngines.Engines.FindPartialView. Here is a portion of the failing test:

var routeData = new RouteData();
routeData.Values.Add("controller", "someName");
routeData.Values.Add("action", "someAction");

var builder = new TestControllerBuilder();
var controller = new ListingController(repository.Object);
builder.RouteData = routeData;
builder.InitializeController(controller);

var result = controller.Foo();
Zavala answered 14/1, 2012 at 0:33 Comment(0)
H
22

You will have to add a mocked view engine to the ViewEngines.Engines collection so that you can mock the FindPartialView call. Here's an example with Rhino Mocks:

var view = MockRepository.GenerateStub<IView>();
var engine = MockRepository.GenerateStub<IViewEngine>();
var viewEngineResult = new ViewEngineResult(view, engine);
engine
    .Stub(x => x.FindPartialView(null, null, false))
    .IgnoreArguments()
    .Return(viewEngineResult);
ViewEngines.Engines.Add(engine);

Then you could assert that the view.Render method was called, intercept its arguments and write some mocked data to this writer and finally assert that your controller action returned this mocked string.

Hydrangea answered 14/1, 2012 at 9:0 Comment(2)
I just smacked myself on the forehead and quoted the V8 commercial. Doh! Thanks for pointing out the obvious that I could not see. Just to be sure, I am being serious, not facetious.Phaeton
In MVC4, you may have to do ViewEngines.Engines.Clear() before adding the mock engine. At least that's what I had to do to get this to work after upgrading from MVC3 to MVC4.Euroclydon

© 2022 - 2024 — McMap. All rights reserved.