2009-08-31 9 views
7

Ich versuche, einen Komponententest für eine Methode zu erstellen, die ein HttpResponse-Objekt als Parameter verwendet. Was ist der richtige Weg, dies zu tun? Ich hoffe, dass Sie erfahrene Tester dort draußen haben, kann mir helfen.Komponententest für eine Methode, die ein HttpResponse-Objekt als Parameter akzeptiert. OutputStream ist nicht verfügbar

Zusätzliche Informationen: Ich habe versucht, ein gefälschtes HttpResponse-Objekt durch Übergabe in einem StringWriter zu erstellen.

StringBuilder sb = new StringBuilder(); 
StringWriter sw = new StringWriter(sb); 
HttpResponse response = new HttpResponse(sw); 
RssGenerator.Generate(response, otherParameters); 

Der Test schlägt fehl mit der Meldung: System.Web.HttpException: Output nicht verfügbar ist, wenn eine benutzerdefinierte Textwriter verwendet wird. Die zu testende Methode ist Teil einer Klassenbibliothek dll. Es verwendet den OutputStream des Response-Objekts, um einen RSSFeed mit einem XMLWriter zu erstellen.

+0

Vielen Dank für alle guten Antworten. Ich werde dich wissen lassen, was ich damit mache. –

Antwort

12

Need Namespace System.Web.Abstractions

Insbesondere zu verwenden, eine Httpresponsebase nehmen (http://msdn.microsoft.com/en-us/library/system.web.httpresponsebase.aspx) als Eingabeparameter anstelle von Httpresponse. Dann können Sie die HttpResponseBase aus Ihren Tests verspotten. Wenn Sie eine echte HttpResponse übergeben möchten, verwenden Sie HttpResponseWrapper, um eine HttpResponseBase zu erzeugen.

+3

Ich brauchte eine Weile, um das zu finden, also hier ist es: HttpResponseWrapper wrapper = new HttpResponseWrapper (this.Response); ist, wie Sie das tun, was Sie beschreiben. HttpResponseWrapper erweitert HttpResponseBase. – Aligned

3

Um wirklich Einheit zu sein, sollten Sie HttpResponse und alles andere nachahmen, um nur Ihren Methodencode zu testen. Ich kenne keine C# -Verbraucher, aber diese question might help.

Sie können dann so etwas tun (Beispiel ist Java mit Mockito):

HttpResponse response = mock(HttpResponse.class); 
OutputStream outputStream = mock(OutputStream.class); 
when(response.getOutputStream()).thenReturn(outputStream); 

RssGenerator.generate(response, otherParameters); 

Natürlich müssen Sie wahrscheinlich Ihre Mock mehr als dies konfigurieren, aber Sie die allgemeine Idee.

1

Der Konstruktor für HttpResponse ist nicht für Ihre Verwendung vorgesehen, sondern nur für den ASP.NET-Seitenzyklus. Daher gibt es keine Dokumentation zur Erstellung eines solchen.

Sie müssen das Objekt HttpResponse so einrichten, dass es HttpWriter verwendet, andernfalls können Sie nicht auf den zugrunde liegenden Stream zugreifen. Allerdings hat der Konstruktor die _httpWriter Variable auf null gesetzt, also müssen Sie eine andere Weise finden, es einzustellen.

Sie können das .NET Reflector Programm verwenden, um in der HttpResponse Klasse zu graben und zu sehen, was es tut.

0

Wenn ich die Methodensignatur nicht refaktorieren konnte (vielleicht benötigt die Methode wirklich nur einen Wert von der HttpResponse?), Hätte ich Eclipse eine Nullimplementierung von HttpResponse erzeugen (ja, ich bin in Java, aber es ist die gleiche Idee) - dh implementiert alle Methoden, die null zurückgeben - und einfach nur diejenigen, die ich brauche in der Methode zu testen, zu füllen, und sie haben einige konstante Werte zurückgeben. (Ja, könnte auch ein spöttisches Framework von irgendeiner Art verwenden.)

Der Grund, warum Sie Ihre eigene Instanz der vorhandenen Implementierung nicht erstellen können, ist stark an Ihren Anwendungsserver gebunden und wird wahrscheinlich alle Arten benötigen von anderen Gunks sogar instanziiert werden.

Wenn es sich herausstellte, ich brauche etwas komplizierter als eine einfache Null-Version von HttpResponse, dann würde ich nicht direkt diese Methode direkt testen: vielleicht ein Test ein oder zwei Stufen höher wäre einfacher und würde mir das gleiche Niveau Vertrauen in den Code.

1

Also das Problem mit Mocking HttpResponse ist, dass es versiegelt ist, so dass Sie es nicht erweitern können (und die meisten spöttischen Frameworks, die konkrete Mock-Klassen überschreiben nur virtuelle Methoden). Microsoft war auch nett genug, keine Schnittstellen für die meisten zu bieten ... also danke MS.

Aus diesem Grund (unter anderem) schreibe ich normalerweise meine eigenen Interfaces für alle versiegelten MS-Klassen und schreibe dann Wrapper-Implementierungen, die die MS-Klasse im Konstruktor nehmen und sie so schnell wie möglich in der Anfrage umleiten. Dann können Sie Mocks der Schnittstellen erstellen und sie tun lassen, was Sie wollen.

1

Wenn Sie eine ausführlichere Antwort wollen, hier ist das, was ich in meinem Projekt endete tun:

_mockResponse = new Mock<HttpResponseBase>(); 
_contentType = string.Empty; 
_mockResponse.SetupSet(r => r.ContentType = It.IsAny<string>()).Callback<string>(value => _contentType = value); 
_header = new KeyValuePair<string, string>(); 
_mockResponse.Setup(r => r.AddHeader(It.IsAny<string>(), It.IsAny<string>())).Callback((string name, string value) => _header = new KeyValuePair<string, string>(name, value)); 
_writer = new StringBuilder(); 
_mockResponse.Setup(r => r.Write(It.IsAny<string>())).Callback<string>(s => _writer.Append(s)); 
var data = "This is the string to send as response"; 

UTIL.SendStringAsHttpResponse(data, _mockResponse.Object); 

Assert.That(_contentType, Is.EqualTo("application/CSV")); 
Assert.That(_header.Value, Is.EqualTo("attachment; filename=download.csv")); 
Assert.That(_writer.ToString(), Is.EqualTo(data)); 

wo SendStringAsHttpResponse definiert als

public static void SendStringAsHttpResponse(string data, HttpResponseBase response) 
Verwandte Themen