Looking for direction on unit testing a controller

2019-02-06 06:31发布

问题:

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

回答1:

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.