MVC 4 Mocking HttpContext - как насмехаться с DisplayModeProvider
В настоящее время я использую контекстный макет Scott Messelmans HTTP для модульного тестирования. Это хорошо работало для MVC 3 и никогда не оглядывалось назад, я использовал его для тестирования вызовов для следующего кода.
public class PartialViewRenderer : IPartialViewRenderer
{
public string Render(Controller controller, string viewName, object model)
{
if (string.IsNullOrEmpty(viewName))
viewName = controller.ControllerContext.RouteData.GetRequiredString("action");
controller.ViewData.Model = model;
using (StringWriter sw = new StringWriter())
{
ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(controller.ControllerContext, viewName);
ViewContext viewContext = new ViewContext(controller.ControllerContext, viewResult.View,
controller.ViewData, controller.TempData, sw);
viewResult.View.Render(viewContext, sw);
return sw.GetStringBuilder().ToString();
}
}
}
Когда я впервые конвертировал свое приложение в MVC 4, я столкнулся с проблемами, он получал исключения во время выполнения. Поэтому я попытался пройти и исправить то, что нужно для исправления, которое приземлило меня на изменение следующих методов на Hanselmans MockHelpers: (Я в основном изменил HttpContext.Items, чтобы получить возврат, поскольку он продувал исключение "null" )
public static HttpContextBase FakeHttpContext()
{
var context = new Mock<HttpContextBase>();
var request = new Mock<HttpRequestBase>();
var response = new Mock<HttpResponseBase>();
var session = new Mock<HttpSessionStateBase>();
var server = new Mock<HttpServerUtilityBase>();
var cookies = new HttpCookieCollection();
var items = new ListDictionary();
request.Setup(r => r.Cookies).Returns(cookies);
response.Setup(r => r.Cookies).Returns(cookies);
context.Setup(ctx => ctx.Items).Returns(items);
context.SetupGet(ctx => ctx.Request).Returns(request.Object);
context.SetupGet(ctx => ctx.Response).Returns(response.Object);
context.SetupGet(ctx => ctx.Session).Returns(session.Object);
context.SetupGet(ctx => ctx.Server).Returns(server.Object);
return context.Object;
}
public static void SetFakeControllerContext(this Controller controller, RouteData route)
{
var httpContext = FakeHttpContext();
ControllerContext context = new ControllerContext(new RequestContext(httpContext, route), controller);
controller.ControllerContext = context;
}
Здесь очень простой тест nUnit, который я должен попытаться прикрепить к тем изменениям, которые мне нужно внести в этот макет контекста http (я даже не добавил в утверждения)
[Test]
public void test()
{
_contactsController = _container.Resolve<ContactsController>();
var route = new RouteData();
route.Values.Add("controller", "ContactsController");
route.Values.Add("action", "GetEditContactDetailsDialog");
_contactsController.SetFakeControllerContext(route);
var result = _contactsController.GetEditContactDetailsDialog("1");
}
Теперь, когда я запускаю этот тест, он бомбит вызов PartialViewRenderer.Render в строке ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(controller.ControllerContext, viewName);
Вот следующая таблица stacktrace.
в System.Web.WebPages.DisplayModeProvider. <.ctor > b__2 (контекст HttpContextBase) в System.Web.WebPages.DefaultDisplayMode.CanHandleContext(HttpContextBase httpContext) в System.Web.WebPages.DisplayModeProvider. < > c__DisplayClass6.b__5 (режим IDisplayMode) в System.Linq.Enumerable.WhereListIterator 1.MoveNext()
at System.Collections.Generic.List
1..ctor(IEnumerable 1 collection)
at System.Linq.Enumerable.ToList[TSource](IEnumerable
1 источник) в System.Web.WebPages.DisplayModeProvider.GetAvailableDisplayModesForContext(HttpContextBase httpContext, IDisplayMode currentDisplayMode) в System.Web.Mvc.VirtualPathProviderViewEngine.GetPath(ControllerContext controllerContext, String [] location, String [] areaLocations, String locationsPropertyName, String name, String controllerName, String cacheKeyPrefix, Boolean useCache, String [] & lookLocations)
Кажется, я не могу попасть туда и высмеивать DisplayModeProvider. В исходном коде MVC У кого-нибудь есть решение? Я не смог найти решение этого в любом месте.
Ответы
Ответ 1
Сначала init издевается с MockBehavior.Strict
как:
var context = new Mock<HttpContextBase>(MockBehavior.Strict);
Используя это, вы можете найти зависимость с DisplayMode.
Во-вторых, DisplayMode - это новая функция в asp.net mvc 4:
http://www.asp.net/whitepapers/mvc4-release-notes#_Toc303253810
Итак, он получает параметры Request.Browser
для определения View, которые используют. Добавить Mock для браузера:
var browser = new Mock<HttpBrowserCapabilitiesBase>(MockBehavior.Strict);
var context = new Mock<HttpContextBase>(MockBehavior.Strict);
var request = new Mock<HttpRequestBase>(MockBehavior.Strict);
var response = new Mock<HttpResponseBase>(MockBehavior.Strict);
var session = new Mock<HttpSessionStateBase>(MockBehavior.Strict);
var server = new Mock<HttpServerUtilityBase>(MockBehavior.Strict);
var cookies = new HttpCookieCollection();
var items = new ListDictionary();
browser.Setup(b => b.IsMobileDevice).Returns(false);
request.Setup(r => r.Cookies).Returns(cookies);
request.Setup(r => r.ValidateInput());
request.Setup(r => r.UserAgent).Returns("Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.64 Safari/537.11");
response.Setup(r => r.Cookies).Returns(cookies);
request.Setup(r => r.Browser).Returns(browser.Object);
context.Setup(ctx => ctx.Items).Returns(items);
Ответ 2
DisplayMode
реализует интерфейс IDisplayMode
, поэтому вы должны иметь возможность (с помощью Moq) создавать ложный ввод. DisplayModeProvider
имеет SetDisplayMode
(защищенный) метод, который вы можете вызвать через Reflection.