2009-08-31 17 views
7

Estoy intentando crear una prueba unitaria para un método que toma un objeto HttpResponse como parámetro. ¿Cuál es la forma correcta de hacer esto? Espero que los probadores de unidades experimentados puedan ayudarme.Prueba unitaria de un método que toma un objeto HttpResponse como parámetro. OutputStream no está disponible

Información adicional: Intenté crear un objeto falso HttpResponse pasando en un StringWriter.

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

la prueba falla con el mensaje: System.Web.HttpException: OutputStream no está disponible cuando se utiliza un TextWriter personalizado. El método que se prueba es parte de una biblioteca de clase dll. Utiliza el OutputStream del objeto Response para crear un RSSFeed con un XMLWriter.

+0

Gracias por todas las buenas respuestas. Te dejaré saber lo que eventualmente haré con esto. –

Respuesta

12

necesidad de utilizar System.Web.Abstractions de espacio de nombres

En particular, tomar un HttpResponseBase (http://msdn.microsoft.com/en-us/library/system.web.httpresponsebase.aspx) como un parámetro de entrada en lugar de HttpResponse. Entonces puede burlarse de HttpResponseBase de sus pruebas. Cuando tiene una HttpResponse real para pasar, use HttpResponseWrapper para producir una HttpResponseBase.

+3

Me tomó un tiempo encontrar esto, así que aquí está: HttpResponseWrapper wrapper = new HttpResponseWrapper (this.Response); es cómo hacer lo que describes. HttpResponseWrapper extiende HttpResponseBase. – Aligned

3

Para ser una verdadera unidad, debe simular HttpResponse y todo lo demás para probar solo el código de métodos. No sé de ninguna utilidad de burla C#, pero esto question might help.

entonces usted puede hacer algo como esto (ejemplo es Java con Mockito):

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

RssGenerator.generate(response, otherParameters); 

Por supuesto, es probable que tenga que configurar el simulacro más que esto, pero usted consigue la idea general.

1

El constructor para HttpResponse no está destinado a su uso, solo está disponible para el ciclo de página ASP.NET, por lo que no hay documentación sobre cómo crearlo.

Tiene que configurar el objeto HttpResponse para que use un HttpWriter, de lo contrario no le permitirá acceder al flujo subyacente. Sin embargo, el constructor estableció la variable _httpWriter en null, por lo que debe buscar otra forma de configurarlo.

Puede usar el programa .NET Reflector para buscar en la clase HttpResponse y ver qué hace.

0

Si no pudiera refactorizar la firma del método (quizás el método realmente solo necesite un valor del HttpResponse?), Haría que Eclipse genere una implementación nula de HttpResponse (sí, estoy en Java, pero es el misma idea) - es decir, implementa todos los métodos que devuelven nulo - y simplemente complete solo los que necesito en el método que se va a probar, y pídales que devuelvan algunos valores constantes. (Sí, podría usar un marco de burla de algún tipo, también.)

La razón por la que no puede crear su propia instancia de la implementación existente es que estará fuertemente ligada a su servidor de aplicaciones, y es probable que necesite todo tipo de otro gunk incluso para ser instanciado.

Si resultó que necesito algo más complicado que una simple versión nula de HttpResponse, entonces miraría NO probar este método directamente: quizás una prueba de uno o dos niveles sería más simple y me proporcionaría el mismo nivel de confianza en el código.

1

Así que el problema con Mocking HttpResponse es que está sellado, por lo que no puedes extenderlo (y la mayoría de los frameworks burlones que simulan las clases concretas simplemente sobrescriben los métodos virtuales). Microsoft también tuvo la amabilidad de no proporcionar interfaces para la mayoría de estos ... así que gracias MS.Por esta razón (entre otras) termino escribiendo mis propias interfaces para todas las clases de MS selladas y luego escribiendo implementaciones de envoltura que toman la clase MS en el constructor y las derivan tan pronto como sea posible en la solicitud. Luego puede crear simulaciones de las interfaces y hacer que hagan lo que quiera.

1

Si desea una respuesta más detallada, aquí es lo que terminó haciendo en mi proyecto:

_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)); 

donde SendStringAsHttpResponse se define como

public static void SendStringAsHttpResponse(string data, HttpResponseBase response) 
Cuestiones relacionadas