Подтвердить что ты не робот

Модуль тестирования моего метода контроллера приводит к пустой ViewName?

Я делаю несколько простых тестов MS на моем стандарте, ничего специального контроллера.

Когда я проверяю свойство ViewName, из возвращаемого объекта ViewResult, он "" (пустой).

У меня создается впечатление, что ViewName подразумевается именем View (как предложенным в этой статье MS при тестировании контроллера ASP.NET MVC).

Кстати, когда я тестирую ViewData, все там и правильно.

Вот код, который у меня есть...

public ActionResult Index(int? page, string tag)
{
    if (page == null || page <= 0)
    {
        page = 1;
    }

    var viewData = new IndexViewData
                       {
                       ... my property setters, etc ...
                       };
    return View(viewData);
}

[TestMethod]
public void Index_Action_Should_Return_Index_View_For_Default_HomePage()
{
    // Arrange.
    var controller = PostController; // Wrapper, cause I use D.I.

    // Act.
    ViewResult viewResult = controller.Index(null, null) as ViewResult;

    // Assert.
    Assert.IsNotNull(viewResult);
    Assert.AreEqual("Index", viewResult.ViewName); // This is false/fails.

    var indexViewData = viewResult.ViewData.Model as IndexViewData;
    Assert.IsNotNull(indexViewData); // This is true.
}
4b9b3361

Ответ 1

ViewName присутствует только при установке в ViewResult. Если ваше имя вида совпадает с вашим именем контроллера, я бы проверил, чтобы ViewName был пустым или пустым, поскольку это было бы (IMO) правильное поведение, так как вы не хотели бы устанавливать имя в представлении. Я проверяю только то, что ViewName устанавливается, когда я намереваюсь, чтобы возвращаемый вид не соответствовал действию - например, при возврате представления "Ошибка", например.

EDIT. Ниже приведен источник ExecuteResult в ViewResultBase.cs(с RC1, у меня нет источника RTW на моем Macintosh). Как вы можете видеть, он проверяет, установлено ли ViewName напрямую, а если нет, он извлекает его из действия в данных маршрута контекста контроллера. Это происходит только в ExecuteResult, который вызывается ПОСЛЕ завершения действия вашего контроллера.

    public override void ExecuteResult(ControllerContext context) {
        if (context == null) {
            throw new ArgumentNullException("context");
        }
        if (String.IsNullOrEmpty(ViewName)) {
            ViewName = context.RouteData.GetRequiredString("action");
        }

        ViewEngineResult result = null;

        if (View == null) {
            result = FindView(context);
            View = result.View;
        }

        ViewContext viewContext = new ViewContext(context, View, ViewData, TempData);
        View.Render(viewContext, context.HttpContext.Response.Output);

        if (result != null) {
            result.ViewEngine.ReleaseView(context, View);
        }
    }

Ответ 2

Я лично обнаружил, что средства тестирования, предоставленные MVC2, несколько неуклюжи. Я предполагаю, что есть что-то лучшее уже существующее, но я закончил создание простого класса для проверки действий. Я смоделировал интерфейс (реализация - еще одна история) на классе, предоставляемом отличным открытым исходным кодом Java MVC framework Stripes под названием MockRoundTrip.

Вот метод, используемый для получения целевой страницы действия при тестировании действий под названием getTripDestination(). Он возвращает правильный результат независимо от того, явно ли указано имя представления или нет

    //Get the destination page of the request, using Runtime execution pattern of MVC, namely
    //if no ViewName is explicitly set in controller, ViewResult will have an empty ViewName
    //Instead, current action name will be used in its place
    public string getTripDestination()
    {
       RouteData routeData = getRouteData();
       ViewResult viewResult = (result is ViewResult) ? (ViewResult)result : null;
       string tripDestination = (viewResult != null) ? viewResult.ViewName : "";

       return (tripDestination != "") ? tripDestination : (String)routeData.Values["action"];
    }

    private RouteData getRouteData()
    {
       HttpContextBase context = controller.ControllerContext.RequestContext.HttpContext;
       return RouteTable.Routes.GetRouteData(context);
    }

Ответ 3

Имя вида автоматически устанавливается каркасом. Но когда мы unit test, мы коротко замыкаем фреймворк и нечего устанавливать имя.

Таким образом, наши действия должны явно указывать имя вида, когда мы unit test. Мы также могли бы проверить наличие пустого или пустого, если мы действительно хотим навязать соглашение.

Ответ 4

Документация для Controller.View() утверждает:

Этот метод перегрузки класса View возвращает объект ViewResult который имеет пустое свойство ViewName. Если вы пишете модульные тесты для действий контроллера, учитывайте пустое свойство ViewName для модульные тесты, которые не принимают имя строки.

Во время выполнения, если свойство ViewName пуст, текущее действие вместо свойства ViewName используется имя.

Поэтому, ожидая представления с тем же именем, что и текущее действие, мы можем просто проверить, что это пустая строка.

В качестве альтернативы метод Controller.View(String) задает ViewName.