2010-11-01 7 views
5

Estoy usando Moq para crear un Mock<HttpResponseBase> para probar un FileResult que estoy creando para mi aplicación MVC2.HttpResponseBase.Headers están vacíos al ejecutar la prueba

En el método de la FileResultWriteFile(HttpResponseBase response), tengo el código siguiente al final:

// Write the final output with specific encoding. 
response.OutputStream.Write(output, 0, output.Length); 
response.AppendHeader("Content-Encoding", encoding); 

Se utilizará utf-8 o gzip dependiendo de la codificación de la cabecera de la petición Accept-Encoding.

Así que en mi prueba, puedo configurar mi Mock<HttpResponseBase> así:

var mockResponse = new Mock<HttpResponseBase>(); 
mockResponse.Setup(r => r.OutputStream).Returns(new MemoryStream()); 
mockResponse.Setup(r => r.Headers).Returns(new NameValueCollection()); 

Pero cuando realmente comprobar que la cabecera se ha establecido, Content-Encodingsiempre devuelve un valor nulo:

var response = mockResponse.Object; 
Assert.AreEqual("utf-8", response.Headers["Content-Encoding"]); 

Lo extraño es que OutputStream obtiene los datos escritos en él y puedo afirmar que está escribiendo el valor correcto.

Lo curioso es que cuando realmente depurar el FileResult en un proyecto web, la cabecera se envía correctamente.

¿Alguien tiene alguna idea de esto? Puedo proporcionar más código si es necesario.

+0

Puede incluir más código sobre la configuración de Moq. – Ahmad

Respuesta

4

Acabé burla el método AppendHeader añadir fuerza la cabecera de la HttpResponseBase ' s cabeceras:

mockResponse 
    .Setup(r => r.AppendHeader(It.IsAny<string>(), It.IsAny<string>())) 
    .Callback((string k, string v) => mockResponse.Object.Headers.Add(k, v)); 

sospecho que hay algo más abajo en el interior de la llamada de AppendHeader que no le gusta la adición de cabeceras sin un real HttpResponseBase en su lugar.

Si hay una idea mejor, se sienten libres de sugerir. Espero que esto ayude a alguien en el futuro.

2

Basado en el código de configuración proporcionada (no estoy seguro si es un error tipográfico), creo que debe decir lo siguiente

var Response = new Mock<HttpResponseBase>(); 
Response.Setup(r => r.OutputStream).Returns(new MemoryStream()); 
Response.Setup(r => r.Headers).Returns(new NameValueCollection()); 
+0

Sí, fue un error tipográfico en la publicación. Lo había nombrado de manera diferente en el código en la publicación que el código real que estaba usando. En el código "real", es una propiedad llamada "Respuesta" de una clase "MockHttpContext" que creé. El código anterior es la * única * parte que modifica el 'Mock '. – TheCloudlessSky

+0

@TheCloudlessSky - mi respuesta es discutible, entonces – Ahmad

+0

Esto funcionó. Es interesante cómo tienes que usar un 'MemoryStream' para configurar los encabezados. Intenté otras cien cosas antes de esto. Gracias, @Ahmad. – Alex

4

El problema que tiene es que ver con el hecho de que usted está tratando de maqueta parcialmente clase HttpResponseBase. La escritura en la secuencia de salida funciona porque la propiedad (OutputStream en este caso) se burla y se accede desde SUT (Sistema bajo prueba).

Sin embargo, cuando te burlas Headers propiedad, sólo es que la propiedad que está siendo burlado y no AppendHeader, que es lo que realmente hace el SUT. Los simulacros predeterminados creados por Moq simplemente completan todos los métodos y propiedades como valores por defecto, por lo que AppendHeader en realidad no hace nada.

Hay dos soluciones a este, primero uno es puramente pruebas de interacción y es mi método preferido. No se burle de Headers, sino que verifique AppendHeader.

Mock<HttpResponseBase> responseMock = new Mock<HttpResponseBase>(); 
//the rest of response setup 
FileResult sut = new MyFileResult(); 
sut.WriteFile(responseMock.Object); 
responseMock.Verify(response=>response.AppendHeader("Content-Encoding", "utf8")); 

segundo enfoque es utilizar burla parcial de Moq, lo que haría que los métodos de clase reales maqueta llamada a un objeto, a no ser que se han establecido de forma explícita.

Mock<HttpResponseBase> responseMock = new Mock<HttpResponseBase>(){ CallBase = true }; 
//the rest of response setup 
FileResult sut = new MyFileResult(); 
sut.WriteFile(responseMock.Object); 
Assert.AreEqual("utf-8", responseMock.Object.Headers["Content-Encoding"]); 

yo preferiría la primera versión por un margen delgado como que está probando su interacción con el marco. La segunda versión es más una prueba basada en estado, por lo que teóricamente ni siquiera necesitas un simulacro, podrías usar la clase real. En el caso de HttpResponseBase, sin embargo, casi tiene sentido ya que su constructor está protegido, por lo que al crear un simulacro, básicamente deriva de él en línea, sin tener que escribir manualmente una prueba doble.

+0

Sí, no me di cuenta de que Moq estaba grabando 'AppendHeader'. El ajuste 'CallBase = true' muestra eso. Me gusta su idea de verificar que * no * configuró el encabezado, pero no * realmente * asegúrese de que el encabezado esté configurado con el estado final que se envía (como usted dijo). Podría accidentalmente llamar a otro 'AppendHeader' y luego sobrescribirlo con otra llamada (aunque creo que podría * verificar * esto también). ¡Gracias por tus pensamientos! – TheCloudlessSky

+0

WriteFile está protegido como puede llamarlo directamente .. –

Cuestiones relacionadas