2012-11-12 16 views
10

Ich war zur Zeit mit Scott Hanselmans HTTP context mock für Komponententests. Dies funktionierte gut für MVC 3 und schaute nie zurück, ich verwendete es für das Testen von Aufrufen für den folgenden Code.MVC 4 Mocking HttpContext - wie Mocking 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(); 
     } 
    } 
} 

Als ich meine App zum ersten Mal in MVC 4 umwandelte, kam es zu Problemen, es gab Laufzeitausnahmen. Also versuchte ich gehen durch und reparieren, was Fixierung benötigt, die mich auf die Änderung der folgenden Methoden landete auf Hanselmans MockHelpers: (Ich änderte im Grunde die HttpContext.Items bekommen zurückgegeben, da es eine Ausnahme von „null“ weht)

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

Hier ist ein sehr einfaches nUnit Test ich habe zu versuchen und festzunageln, welche Änderungen ich auf diese spotten http Kontext zu machen brauchen

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

Now (ich selbst in der behauptet noch gestellt haben), wenn ich diesen Test ausführen Es bombardiert den Aufruf von PartialViewRenderer.Render in Zeile ViewEngineResult viewResult = ViewEngines.Engines.FindPartialView(controller.ControllerContext, viewName); Hier ist der folgende StackTrace.

bei System.Web.WebPages.DisplayModeProvider. < .ctor> b__2 (HttpContextBase-Kontext) bei System.Web.WebPages.DefaultDisplayMode.CanHandleContext (HttpContextBase httpContext) bei System.Web.WebPages.DisplayModeProvider. <> c__DisplayClass6.b__5 (IDisplayMode Modus) bei System.Linq.Enumerable.WhereListIterator 1.MoveNext() at System.Collections.Generic.List 1..ctor (IEnumerable 1 collection) at System.Linq.Enumerable.ToList[TSource](IEnumerable 1 Quelle) bei System.Web.WebPages.DisplayModeProvider.GetAvailableDisplayModesForContext (Httpcontextbase Httpcontext, IDisplayMode currentDisplayMode) bei System .Web.Mvc.VirtualPathProviderViewEngine.GetPath (Controllercontroller, String [] Standorte, String [] areaLocations, String locationsPropertyName, name String, String controller, String cacheKeyPrefix, Boolean useCache, String [] & searchedLocations)

Es Scheint, ich kann nicht reinkommen und den DisplayModeProvider verspotten. Per the MVC source Code Hat jemand eine Lösung dafür? Ich konnte nirgendwo eine Lösung finden.

+0

Ich habe ein ähnliches Problem in Bezug auf Mocking DisplayMode. Ich frage mich, ob Sie irgendeine Lösung finden könnten? – Shahin

Antwort

0

DisplayMode implementiert die Schnittstelle IDisplayMode, so dass Sie in der Lage sein sollten (mit Moq) erstellen Sie einen Schein zu injizieren. DisplayModeProvider hat eine SetDisplayMode (geschützte) Methode, die Sie möglicherweise über Reflection aufrufen können.

6

Zuerst init spottet mit MockBehavior.Strict wie:

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

Mit diesem Sie Abhängigkeit mit Display finden.

Zweitens ist Display neue Funktion in asp.net MVC 4:

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

Also, es Request.Browser params für bestimmte Ansicht, die Verwendung bekommen. Add Mock für den Browser:

 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

Ich muss das noch zur Arbeit bringen. Ich bekomme jetzt einen weiteren Fehler, ich hoffe, dass ich das heute Abend herausfinden kann. – Etch

+0

Danke, dieser Code funktioniert wie ein Zauber. – msi

+0

Es scheint etwas zu fehlen, wenn "ViewEngineCollection.FindPartialView()" aufgerufen wird, da es mit "NullReferenceException" im System.Web.Web.Pages.FileExcistenceCache-Konstruktor fehlschlägt. Diese Antwort mag in anderen Szenarien wie ein Zauber funktionieren, nur nicht (noch) in dem Fall, den ich beobachte. – Manfred