2012-11-12 16 views
10

Używałem obecnie Scott Hanselmans HTTP context mock do testowania urządzenia. To działało dobrze dla MVC 3 i nigdy się nie obejrzało, użyłem go do testowania wywołań dla następującego kodu.MVC 4 Makiety HttpContext - jak kpić DisplayModeProvider

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(); 
     } 
    } 
} 

Kiedy po raz pierwszy skonwertowałem swoją aplikację do MVC 4, napotkaliśmy problemy, otrzymywałem wyjątki runtime. Próbowałem więc przejść i naprawić to, co wymagało poprawienia, co spowodowało zmianę następujących metod na Hanselmans MockHelpers: (Zasadniczo zmieniłem HttpContext.Items, aby uzyskać zwrot, ponieważ był to wyjątek "zerowy")

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; 
    } 

Oto bardzo prosty test NUnit muszę spróbować i paznokci w dół, jakie zmiany muszę zrobić z tym mock kontekstu http (i miałaś nawet umieścić w jeszcze twierdzi)

[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"); 
    } 

teraz, kiedy uruchomić ten test bomba na wywołanie PartialViewRenderer.Render on-line ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(controller.ControllerContext, viewName); Oto następujący stacktrace.

w System.Web.WebPages.DisplayModeProvider. < .ctor> b__2 (kontekst HttpContextBase) w System.Web.WebPages.DefaultDisplayMode.CanHandleContext (HttpContextBase httpContext) w System.Web.WebPages.DisplayModeProvider. <> c__DisplayClass6.b__5 (tryb IDisplayMode) w System.Linq.Enumerable.WhereListIterator 1.MoveNext() at System.Collections.Generic.List 1..ctor (IEnumerable 1 collection) at System.Linq.Enumerable.ToList[TSource](IEnumerable 1 źródło) w System.Web.WebPages.DisplayModeProvider.GetAvailableDisplayModesForContext (HttpContextBase HTTPContext, IDisplayMode currentDisplayMode) W układzie .Web.Mvc.VirtualPathProviderViewEngine.GetPath (ControllerContext controllerContext, String [String] Lokalizacje, [] areaLocations, łańcuch locationsPropertyName, nazwa String Ciąg controllerName, String cacheKeyPrefix, logiczna useCache, String [] & searchedLocations)

ramę wydaje się, że nie mogę się tam dostać i kpić z DisplayModeProvider. Per the MVC source Code Czy ktoś ma rozwiązanie tego problemu? Nigdzie nie mogłem znaleźć rozwiązania.

+0

Mam podobny problem dotyczący szyderstwa DisplayMode. Zastanawiam się, czy mógłbyś znaleźć jakieś rozwiązanie? – Shahin

Odpowiedz

0

DisplayMode implementuje interfejs IDisplayMode, więc powinieneś być w stanie (z Moq) stworzyć próbę do wstrzyknięcia. DisplayModeProvider ma metodę SetDisplayMode (chronioną), którą możesz wywołać za pomocą Reflection.

6

pierwsze, init kpi z MockBehavior.Strict jak:

var context = new Mock<HttpContextBase>(MockBehavior.Strict); 

Korzystanie może znaleźć zależność z DisplayMode.

drugie, DisplayMode jest nowością w ASP.NET MVC 4:

http://www.asp.net/whitepapers/mvc4-release-notes#_Toc303253810

Tak, to dostać Request.Browser params na widok których stosowanie zdeterminowanej. Dodaj Mock dla przeglądarki:

 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); 
+0

Muszę jeszcze to zrobić. Teraz dostaję kolejny błąd, mam nadzieję, że uda mi się to rozgryźć dzisiejszego wieczoru. – Etch

+0

Dzięki, ten kod działa jak czar. – msi

+0

Wydaje się, że czegoś brakuje podczas wywoływania 'ViewEngineCollection.FindPartialView()', ponieważ kończy się niepowodzeniem z 'NullReferenceException' w konstruktorze System.Web.Web.Pages.FileExcistenceCache. Ta odpowiedź może działać w innych scenariuszach, takich jak urok, ale nie (jeszcze) w przypadku, który obserwuję. – Manfred