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

Добавить ключи и значения в RouteData при использовании MVCContrib для unit test контроллеров MVC 3 и представлений

Хорошо, поэтому я использую MVCContrib TestHelper для unit test моих контроллеров, который отлично работает.

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

Во всяком случае, я начал пытаться выяснить, как это сделать (ака-роуглинг, как это сделать). Казалось, что самый простой способ - создать HTMLHelper и просто визуализировать представления (частичные в этом случае).

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

Конечно, я смотрю, а контроллеры RouteData не заполняются. К сожалению, RouteData.Values ​​RouteValueDictionary доступен только для чтения, поэтому я не могу просто предоставить необходимые значения.

Я не женат на идее HTMLHelper, чтобы решить проблему фактического представления представления как части теста, поэтому не стесняйтесь предлагать альтернативы там, но, пожалуйста, не утруждайте себя предложением проверить мои взгляды, используя Selenium, Watin или другие инструменты тестирования пользовательского интерфейса... Я хочу, чтобы элемент управления мог выполнять такие действия, как манипулирование и восстановление информации о состоянии и данных для некоторых тестов, что я не могу сделать с тестированием на основе интерфейса.

Вот код, который я сейчас использую, чтобы попытаться отобразить частичное:

    public class FakeView : IView
{
    #region IView Members
    public void Render(ViewContext viewContext, System.IO.TextWriter writer)
    {
        throw new NotImplementedException();
    }
    #endregion
}

public class WebTestUtilities
{
    public static void prepareCache()
    {
        SeedDataManager seed = new SeedDataManager();
        seed.CheckSeedDataStatus();
    }

    public static string RenderRazorViewToString(string viewName, object model, Controller controller)
    {
        var sb = new StringBuilder();
        var memWriter = new StringWriter(sb);
        var html = new HtmlHelper(new ViewContext(controller.ControllerContext,
            new FakeView(), new ViewDataDictionary(), new TempDataDictionary(), memWriter),
            new ViewPage());
        //This fails because it can't extract route information like the controller name)
        html.RenderPartial(viewName, model);
        return sb.ToString();
    }


    public void setupTestEnvironment(Controller controller)
    {
        RouteTable.Routes.Clear();
        RouteTable.Routes.IgnoreRoute("{resource}.axd/{*pathInfo}");

        RouteTable.Routes.MapRoute(
            "Default", 
            "{controller}/{action}/{id}", 
            new { controller = "Main", action = "DefaultView", id = UrlParameter.Optional } 
        );




        ModelBinders.Binders[typeof(DateTime)] = new DateTimeModelBinder();
        ModelBinders.Binders[typeof(DateTime?)] = new DateTimeModelBinder();
        ModelMetadataProviders.Current = new DateTimeMetadataProvider();



    }
}

И вот мой метод тестирования:

        [TestMethod]
    public void GetUserTableView()
    {
        ViewResult result = controller.UserTable() as ViewResult;

        //I can populate the route and handler on the controller...
        RouteData routes = RouteTable.Routes.GetRouteData(controller.HttpContext);
        controller.RouteData.Route = routes.Route;
        controller.RouteData.RouteHandler = routes.RouteHandler;
        RouteValueDictionary routeKeys = new RouteValueDictionary();
        routeKeys.Add("controller", "UserManagement");
        routeKeys.Add("action", "UserTable");
        //But the RouteData.Values collection is read only :(
        controller.RouteData = new RouteData(){Values = routeKeys};
        string renderedView = WebTestUtilities.RenderRazorViewToString(result.ViewName, result.Model, controller);
    }

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

4b9b3361

Ответ 1

Возможно, вы уже это проделали, но у меня была аналогичная проблема, и я решил настроить RouteData, сбросив ControllerContext на контроллер следующим образом:

RouteData routeData = new RouteData();
routeData.Values.Add("someRouteDataProperty", "someValue");
ControllerContext controllerContext = new ControllerContext { RouteData = routeData };
controller.ControllerContext = controllerContext;

а затем в контроллере RouteData.Values.ContainsKey( "someRouteDataProperty" ) работает так, как вы установили в тесте.

Это работает, потому что есть конструктор без параметров, созданный ControllerContext, который намеренно существует, чтобы вызывать насмешку и т.д.

Ответ 2

Вы можете переопределить контроллеры ControllerContext.RouteData - его виртуальное свойство и свойство RouteData просто используют его для чтения.

Из отраженного кода свойства asp.net mvc RouteData:

public RouteData RouteData 
{ 
    get 
    {
        return ControllerContext == null ? null : ControllerContext.RouteData; 
    }
}