2010-03-09 4 views
24

Ich habe den Prozess der Bereinigung unseres Controller-Codes durchgearbeitet, um jede Aktion als testbar zu machen. Im Allgemeinen war das nicht allzu schwierig - wo wir die Möglichkeit haben, ein festes Objekt zu benutzen, wie zum Beispiel FormsAuthentication, führen wir im Allgemeinen eine Art von Wrapper ein und sind auf unserem fröhlichen Weg.Ist HttpContextWrapper all das .... nützlich?

Aus Gründen, die nicht besonders wichtig für diese Konversation waren, haben wir uns bei der Verwendung von HttpContext entschieden, die neu erstellte HttpContextWrapper-Klasse zu verwenden, anstatt etwas Eigenes zu erfinden. Eine Sache, die wir eingeführt haben, war die Möglichkeit, einen HttpContextWrapper (wie zum Beispiel für Unit-Tests) zu tauschen. Dies wurde vollständig von der Art und Weise inspiriert Oren Eini Griffe Unit-Tests mit Datetime (see article, ein Muster, das wir verwenden auch)

public static class FooHttpContext 
{ 
    public static Func<HttpContextWrapper> Current =() 
     => new HttpContextWrapper(HttpContext.Current); 

    public static void Reset() 
    { 
     Current =() => new HttpContextWrapper(HttpContext.Current); 
    } 
} 

Nichts besonders extravagant. Und es funktioniert gut in unserem Controller-Code. Der Kicker kam, als wir Unit Tests schreiben. Wir verwenden Moq als unsere Mockframework, aber leider

var context = new Mock<HttpContextWrapper>() 

bricht seit HttpContextWrapper keinen parameterlos Ctor. Und was braucht es als Kernparameter? Ein HttpContext-Objekt. So finde ich mich in einem Fang 22.

Ich verwende den vorgeschriebenen Weg, um HttpContext zu entkoppeln - aber ich kann einen Wert in nicht verspotten, weil das ursprüngliche HttpContext-Objekt versiegelt und daher schwierig zu testen war. Ich kann HttpContextBase abbilden, von denen beide abgeleitet sind - aber das bringt mich nicht wirklich dazu, wonach ich suche. Verpasse ich gerade den Punkt irgendwo in Bezug auf HttpContextWrapper?

bearbeitet Absicht zu klären

Wir Wege gefunden, um das Problem zu lösen - aber ich denke, die ultimative Frage, mit denen wir zu Fuß entfernt ist, was Wert HttpContextWrapper auf den Tisch bringt? Ich zweifle nicht, dass jemand irgendwo ein A-ha hat! Moment damit, aber es kommt einfach nicht zu mir. Die meisten Postings, die ich hier sehe, diskutieren es in Bezug auf Testbarkeit - aber meine eigene Erfahrung hat mich dazu gebracht zu glauben, dass es in diesem Zusammenhang nicht viel gebracht hat. Es sei denn, wir machen es falsch. (Vollkommen möglich).

Antwort

30

Sie sollten die abstrakte HttpContextBase verwenden, die viel einfacher zu verspotten ist als HttpContextWrapper.

public static Func<HttpContextBase> Current = 
    () => new HttpContextWrapper(HttpContext.Current); 

Und in Ihrem Gerät zu testen:

SomeClass.Current = MockHttpContextBase(); // Sorry I don't know the syntax for Moq 
+0

Sie‘ absolut richtig - und was wir letztendlich gemacht haben ... aber meine Frage war eher, was Wrapper wirklich auf den Tisch bringt - lass mich zur besseren Übersicht bearbeiten. – bakasan

+1

'HttpContextWrapper' ist keine Abstraktion, sondern eine konkrete Implementierung von' HttpContextBase'. Ich denke, es ist ein Wert, dass es einige statische und interne Methoden von 'HttpContext' versteckt. –

+7

'HttpContextWrapper' implementiert die (mockbare)' HttpContextBase' durch Weiterleiten von Aufrufen an den ASP.NET-vintage 'HttpContext'. Es ist eine Warze, um die Tatsache zu umgehen, dass 'HttpContext' nicht vorstellbar ist. –

31

Dieser Blog-Eintrag erklärt es ziemlich gut:

http://splinter.com.au/httpcontext-vs-httpcontextbase-vs-httpcontext

Der Punkt ist, dass 'Vintage' Httpcontext nicht Httpcontextbase nicht implementiert, und ist nicht virtuell und kann daher nicht verspottet werden. HttpContextBase wurde in 3.5 als eine mockfähige Alternative eingeführt. Aber es gibt immer noch das Problem, dass Vintage HttpContext HttpContextBase nicht implementiert.

So ist HttpContextWrapper eine handliche Wrapper-Klasse (oder ‚Flickschusterei‘), die Httpcontextbase nicht implementiert und kann verwendet werden, wenn eine ‚echte‘ Injektion Httpcontext IOC, in der Regel mit einem Factory-Methode wie folgt aus: () => new HttpContextWrapper(HttpContext.Current)

+4

Und Sie würden die Registrierung in Unity wie folgt einrichten; 'var container = new UnityContainer(); container.RegisterType (neuer InjectionConstructor (HttpContext.Current)); ' –