Как издеваться над Request.ServerVariables с помощью MOQ для ASP.NET MVC?

Я просто участвую в модульном тестировании для моего asp.net mvc, когда я пришел, чтобы узнать о макетах и ​​разных фреймворках, которые есть там сейчас.

после проверки SO, я обнаружил, что MOQ, кажется, легче всего подбирать. на данный момент я застреваю, пытаясь издеваться над Request.ServerVariables, как после прочтения этого сообщения, я узнал, что лучше абстрагировать их на свойство.

как таковой:

/// <summary>
        /// Return the server port
        /// </summary>
        protected string ServerPort
        {
            get
            {
                return Request.ServerVariables.Get("SERVER_PORT");
            }
        }

Но мне сложно учиться правильно издеваться над этим. У меня есть функция ActionResult для домашнего контроллера, которая захватывает информацию о пользовательском сервере и приступает к созданию формы для захвата информации пользователя.

Я попытался использовать класс hanselman mvcmockhelpers, но я не уверен, как его использовать.

вот что я до сих пор...

[Test]
        public void Create_Redirects_To_ProductAdded_On_Success() 
        {

            FakeViewEngine engine = new FakeViewEngine();

            HomeController controller = new HomeController();
            controller.ViewEngine = engine;

            MvcMockHelpers.SetFakeControllerContext(controller);

            controller.Create();

            var results = controller.Create();

            var typedResults = results as RedirectToRouteResult;

            Assert.AreEqual("", typedResults.RouteValues["action"], "Wrong action");
            Assert.AreEqual("", typedResults.RouteValues["controller"], "Wrong controller");
        }

Вопросы:

  • На данный момент я все еще получаю null ошибка исключения, когда я запускаю контрольная работа. Итак, что мне здесь не хватает?
  • И если я использую mvcmockhelpers класс, как я могу позвонить request.verifyall для обеспечения все издевательски настроены правильно?

Ответ 1

так что в основном я включил все ссылки и используя эту функцию, я смог заставить ее работать. Я не использовал класс mvcmockhelpers пока я все еще пытаюсь узнать все это.

и для тех, кто заинтересован посмотреть, как я это решил, это код, который я использовал.

[Test]
public void Create_Returns_ViewResult_On_Success() 
{
  var server = new Mock<HttpServerUtilityBase>(MockBehavior.Loose);
  var response = new Mock<HttpResponseBase>(MockBehavior.Strict);

  var request = new Mock<HttpRequestBase>(MockBehavior.Strict);
  request.Setup(x => x.ApplicationPath).Returns("/");
  request.Setup(x => x.Url).Returns(new Uri("http://localhost"));
  request.Setup(x => x.ServerVariables).Returns(new System.Collections.Specialized.NameValueCollection{
    { "SERVER_NAME", "localhost" },
    { "SCRIPT_NAME", "localhost" },
    { "SERVER_PORT", "80" },
    { "HTTPS", "www.melaos.com" },
    { "REMOTE_ADDR", "127.0.0.1" },
    { "REMOTE_HOST", "127.0.0.1" }
  });

  var context = new Mock<HttpContextBase>();
  context.SetupGet(x => x.Request).Returns(request.Object);
  context.SetupGet(x => x.Response).Returns(response.Object);
  context.SetupGet(x => x.Server).Returns(server.Object);

  var controller = new HomeController();
  //MvcMockHelpers.SetFakeControllerContext(controller);
  controller.ControllerContext = new ControllerContext(context. Object, new RouteData(), controller);

  var results = controller.Create();
  Assert.IsNotNull(results);
  Assert.IsInstanceOf(typeof(ViewResult), results);
}

Ответ 2

Поскольку я хочу издеваться над HttpContext, а не с HttpContextBase, я попытался найти способ преобразования объекта HttpContextBase в HttpContext и обнаружил, что это невозможно сделать.

HttpContext

Это винтажный контекст asp.net. Проблема в том, что это не имеет базового класса и не является виртуальным и, следовательно, непригодным для тестирования (не может издеваться над ним). Он рекомендовал не передавать его как функцию аргументы, вместо этого передавайте переменные типа HttpContextBase.

HttpContextBase

Это замена (new to С# 3.5) для HttpContext. Поскольку это абстрактно, теперь он макет. Идея состоит в том, что ваши функции, которые ожидая, что данный контекст должен получить один из них. Он конкретно реализован HttpContextWrapper

HttpContextWrapper

Также новый в С# 3.5 - это конкретная реализация HttpContextBase. Чтобы создать один из них на обычной веб-странице, используйте новые HttpContextWrapper (HttpContext.Current).

Идея состоит в том, что для того, чтобы сделать ваш блок модулем работоспособным, вы объявляете все свои переменные и функциональные параметры типа HttpContextBase и используйте схему IOC, например Castle Windsor, чтобы получить инъекцию. В нормальном код, замок, чтобы ввести эквивалент 'нового HttpContextWrapper (HttpContext.Current) ', тогда как в тестовом коде вы чтобы получить макет HttpContextBase.

(источник: http://www.splinter.com.au/httpcontext-vs-httpcontextbase-vs-httpcontext/)

Итак, я изменяю способ вызова своего кода.

Используя HttpContext:

public static string GetIpAddress(HttpContext currentContext) {
 ...
}

Чтобы использовать HttpContextBase:

public static string GetIpAddress(HttpContextBase currentContext) {
 ...
}

И когда я использую этот метод, я переношу HttpContext на HttpContextWrapper следующим образом:

var ip = GeneralUtil.GetIpAddress(new HttpContextWrapper(HttpContext.Current));

Теперь вы можете легко высмеять HttpContextBase, выполнив ответ Дэн Аткинсон