Тестирование NUnit MVC Controller возвращает нулевое представление - PullRequest
1 голос
/ 10 октября 2011

Мое действие HomeController.Index () работает (при нормальной работе), но при тестировании NUnit возвращаемое ActionResult (ViewResult) всегда имеет нулевые View и ViewName.

Вот тесты, которые я выполняю (сведены в единый метод для удобства чтения).

  • Я использую Moq, NUnit, Castle.Windsor
  • Модель результата верна, но с результатом нет представления, связанного с результатом.
  • Все утверждения утвержденыкроме последнего, который ссылается на результат. Вид.

Повторяю для ясности - в нормальном режиме возвращается правильный вид.

[Test]
public void WhenHomeControllerIsInstantiated()
{
    Moch mochRepository = new Mock<IRepository>();
    mochRepository.Setup(s => s.Staff.GetStaffByLogonName("twehr"))
                  .Returns(new Staff { StaffID = 5, LogonName = @"healthcare\twehr" });

    IController controller = new HomeController(mochRepository.Object);

    IPrincipal FakeUser = new GenericPrincipal(new GenericIdentity("twehr", "Basic"), null);
    var result = ((HomeController)controller).Index(FakeUser) as ViewResult;

    Assert.IsNotNull(controller);
    Assert.IsInstanceOf(typeof(HomeController), controller);

    Assert.IsInstanceOf(typeof(HomeViewModel), ((ViewResult)result).Model);

    // result.View and result.ViewName are always null
    Assert.AreEqual("Index", result.ViewName);
}

Очевидно, я что-то пропускаюв настройках теста, но не могу найти его.Любая помощь приветствуется.

Ответы [ 2 ]

3 голосов
/ 12 октября 2011

Причина, по которой result.View имеет значение null, заключается в том, что вы еще не выполнили результат просмотра в контексте контроллера, вы просто вызвали метод действия непосредственно в тесте, который возвращает ViewResult, готовый для выполнения MVC.framework.

Причина, по которой result.ViewName имеет значение null, заключается в том, что вы не указали его явно в методе действия.

Платформа MVC вызывает ExecuteResult (контекст ControllerContext) для возвращенного ViewResult, которыйзатем заполняет ViewName (если NULL) и ищет представление для отображения, вызывая FindView (context), который заполняет View.

Посмотрите на код MVC здесь, и вы могли бы понять его немного лучше:

// System.Web.Mvc.ViewResultBase
public override void ExecuteResult(ControllerContext context)
{
    if (context == null)
    {
        throw new ArgumentNullException("context");
    }
    if (string.IsNullOrEmpty(this.ViewName))
    {
        this.ViewName = context.RouteData.GetRequiredString("action");
    }
    ViewEngineResult viewEngineResult = null;
    if (this.View == null)
    {
        viewEngineResult = this.FindView(context);
        this.View = viewEngineResult.View;
    }
    TextWriter output = context.HttpContext.Response.Output;
    ViewContext viewContext = new ViewContext(context, this.View, this.ViewData, this.TempData, output);
    this.View.Render(viewContext, output);
    if (viewEngineResult != null)
    {
        viewEngineResult.ViewEngine.ReleaseView(context, this.View);
    }
}

Как Zasz заявляет выше, если вы возвращаете ViewResult в своем контроллере, явно указав ViewName, вы можете проверить его в своем тесте.

Например, вместо того, чтобы делать

return View(model);

do

return View("Index", model);

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

HomeController controller = new HomeController();

ViewResult result = controller.Index() as ViewResult;
Assert.IsNotNull(result); // Asserts that result is of type ViewResult since it will be null otherwise

// TODO: Add assertions on the model
// ...
2 голосов
/ 10 октября 2011

Ваш тест очень странный. Для меня эти заявления выглядят бесцельными:

Assert.IsNotNull(controller);
Assert.IsInstanceOf(typeof(HomeController), controller);

Что вы здесь тестируете? А что это за кастинг здесь, при использовании интерфейса выше:

((HomeController)controller)

Зачем тогда использовать интерфейс выше? Почему метод Index возвращает ActionResult (я предполагаю), когда вы можете изменить его, чтобы он возвращал ViewResult согласно вашему случаю? Будьте конкретны и используйте суперкласс ActionResult только тогда, когда действие может вернуть более одного вида результата. Вы можете избежать этого броска ((ViewResult)result)

И как ответ на ваш вопрос:

result.ViewName и т. Д., Заполняется, только если вы явно вызываете метод View () в контроллере следующим образом:

View("Index", model)

Если вы вызываете просто View (), вы зависите от фреймворка для отображения правильного представления на основе соглашения - и вам НЕ нужно тестировать функциональность фреймворка - поэтому проверяйте только содержимое модели , Доверяйте MVC для отображения правильного представления - MVC не выполняет заполнение свойства ViewName, вместо этого он проверяет, является ли свойство пустым, если это так, выполняется и использует соглашение для отображения представления, в противном случае отображается то, что вы указали.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...