Как мне высмеять контекст контроллера в моем unit test, чтобы работать с частичным представлением на функцию строки?

Я пытаюсь создать unit test для моего контроллера, но действие, которое я тестирую, использует частичное представление для строковой функции, которая не хочет работать в моих тестах.

private string RenderPartialViewToString(string viewName, object model = null)
{
   if (string.IsNullOrEmpty(viewName))
            viewName = ControllerContext.RouteData.GetRequiredString("action");

   ViewData.Model = model;

   using (System.IO.StringWriter sw = new System.IO.StringWriter())
   {
      ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(ControllerContext, viewName);
      ViewContext viewContext = new ViewContext(ControllerContext, viewResult.View, ViewData, TempData, sw);
      viewResult.View.Render(viewContext, sw);

      return sw.GetStringBuilder().ToString();
   }
}

Это дает мне ошибку "Ссылка на объект, не установленную на экземпляр объекта" в строке ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(ControllerContext, viewName);

Моя настройка в unit test для контроллера (с удалением нескольких бит для упрощения):

var mock = new Mock<ControllerContext>();
mock.SetupGet(p => p.HttpContext.User.Identity.Name).Returns(userName);
if (userName != null)
{
   mock.SetupGet(p => p.HttpContext.Request.IsAuthenticated).Returns(true);
   mock.SetupGet(p => p.HttpContext.User.Identity.IsAuthenticated).Returns(true);
}
else
{
   mock.SetupGet(p => p.HttpContext.Request.IsAuthenticated).Returns(false);
}
var controller = new BlogController();
controller.ControllerContext = mock.Object;

Мне не удавалось найти решение или работать. Любая помощь оценивается. Спасибо.


Как я уже сказал, я попытался настроить данные маршрута, но все еще получаю ошибку. Это то, что я добавил:

var routeData = new RouteData();
routeData.Values.Add("controller", "BlogController");
mock.SetupGet(m => m.RouteData).Returns(routeData);

Ответ 1

Окончательное решение благодаря помощи в комментариях.

var mock = new Mock<ControllerContext>();
mock.SetupGet(p => p.HttpContext.User.Identity.Name).Returns(userName);
if (userName != null)
{
   mock.SetupGet(p => p.HttpContext.Request.IsAuthenticated).Returns(true);
   mock.SetupGet(p => p.HttpContext.User.Identity.IsAuthenticated).Returns(true);
}
else
{
   mock.SetupGet(p => p.HttpContext.Request.IsAuthenticated).Returns(false);
}

var routeData = new RouteData();
routeData.Values.Add("controller", "BlogController");
mock.SetupGet(m => m.RouteData).Returns(routeData);

var view = new Mock<IView>();
var engine = new Mock<IViewEngine>();
var viewEngineResult = new ViewEngineResult(view.Object, engine.Object);
engine.Setup(e => e.FindPartialView(It.IsAny<ControllerContext>(), It.IsAny<string>(), It.IsAny<bool>())).Returns(viewEngineResult);
ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(engine.Object);

var controller = new BlogController();
controller.ControllerContext = mock.Object;

Ответ 2

Здесь используется версия с использованием AutoMoq, которая отображает строку по вашему выбору.

Subject.ControllerContext = new ControllerContext(
    Mocked<HttpContextBase>().Object,
    new RouteData(),
    Subject);

ViewEngines.Engines.Clear();
ViewEngines.Engines.Add(Mocked<IViewEngine>().Object);
Mocked<IViewEngine>()
    .Setup(x => x.FindPartialView(Subject.ControllerContext,
                                  It.IsAny<string>(), It.IsAny<bool>()))
    .Returns(new ViewEngineResult(Mocked<IView>().Object,
                                  Mocked<IViewEngine>().Object));
Mocked<IView>()
    .Setup(x => x.Render(It.IsAny<ViewContext>(), It.IsAny<TextWriter>()))
    .Callback((ViewContext c, TextWriter w) => w.WriteLine("RENDERED"));