¿Cómo me burlo de HttpContext en ASP.NET MVC usando Moq?

101
[TestMethod]
public void Home_Message_Display_Unknown_User_when_coockie_does_not_exist()
{
    var context = new Mock<HttpContextBase>();
    var request = new Mock<HttpRequestBase>();
    context
        .Setup(c => c.Request)
        .Returns(request.Object);
    HomeController controller = new HomeController();

    controller.HttpContext = context; //Here I am getting an error (read only).
    ...
 }

mi controlador base tiene una anulación del Initialize que obtiene este requestContext. Estoy tratando de transmitir esto pero no estoy haciendo algo bien.

protected override void Initialize(System.Web.Routing.RequestContext requestContext)
{
    base.Initialize(requestContext);
}

¿Dónde puedo obtener más información sobre cómo burlarme de RequestContext y HttpContext usando Moq? Estoy tratando de burlarme de las cookies y del contexto general.

Geo
fuente

Respuestas:

61

HttpContext es de solo lectura, pero en realidad se deriva de ControllerContext, que puede configurar.

 controller.ControllerContext = new ControllerContext( context.Object, new RouteData(), controller );
tvanfosson
fuente
Este funcionó para mí al permitirme establecer un HttpContext simulado en el controlador.
Joel Malone
39

Cree una solicitud, respuesta y colóquelos en HttpContext:

HttpRequest httpRequest = new HttpRequest("", "http://mySomething/", "");
StringWriter stringWriter = new StringWriter();
HttpResponse httpResponse = new HttpResponse(stringWriter);
HttpContext httpContextMock = new HttpContext(httpRequest, httpResponse);
0100110010101
fuente
La pregunta es sobre las clases * Base, es decir, HttpRequestBase, no HttpRequest - no estoy seguro de por qué ambos son necesarios y es aún más molesto que estén "sellados". No hay forma de configurar LogonUserIdentity :(
Chris Kimpton
Si ordenaron mi referencia, aún es posible a través de la comunicación remota, por lo que no debería ser un problema.
0100110010101
1
@ChrisKimpton: Como último recurso, siempre hay reflexión ;-)
Oliver
Esto funciona al adjuntarlo al controlador, así: controller.ControllerContext = new ControllerContext (new HttpContextWrapper (httpContextMock), new RouteData (), controller);
Andreas Vendel
si. de hecho, puede establecer .LogonUserIdentity - _request.Setup (n => n.LogonUserIdentity) .Returns ((WindowsIdentity.GetCurrent));
KevinDeus
12

Gracias usuario 0100110010101.

Funcionó para mí y aquí tuve un problema al escribir el caso de prueba para el siguiente código:

 var currentUrl = Request.Url.AbsoluteUri;

Y aquí están las líneas que resolvieron el problema.

HomeController controller = new HomeController();
//Mock Request.Url.AbsoluteUri 
HttpRequest httpRequest = new HttpRequest("", "http://mySomething", "");
StringWriter stringWriter = new StringWriter();
HttpResponse httpResponse = new HttpResponse(stringWriter);
HttpContext httpContextMock = new HttpContext(httpRequest, httpResponse);
controller.ControllerContext = new ControllerContext(new HttpContextWrapper(httpContextMock), new RouteData(), controller);

Podría ser útil para los demás.

Chandan Kumar
fuente
Parece que no puedo usar el tipo HttpRequest, ¿eso es algo más ahora?
Vincent Buscarello
1
Esto no es útil porque todos los campos en HttpRequest son inmutables
A br
6

Aquí hay un ejemplo de cómo puede configurar esto: Mocking HttpContext HttpRequest y HttpResponse para UnitTests (usando Moq)

Tenga en cuenta los métodos de extensión que realmente ayudan a simplificar el uso de estas clases de burla:

var mockHttpContext = new API_Moq_HttpContext();

var httpContext = mockHttpContext.httpContext();

httpContext.request_Write("<html><body>".line()); 
httpContext.request_Write("   this is a web page".line());  
httpContext.request_Write("</body></html>"); 

return httpContext.request_Read();

Aquí hay un ejemplo de cómo escribir una prueba unitaria usando moq para verificar que un HttpModule está funcionando como se esperaba: Prueba unitaria para HttpModule usando Moq para envolver HttpRequest

Actualización: esta API se ha refactorizado a

Dinis Cruz
fuente
Los enlaces están rotos - incluya el código en su respuesta
Hades
5

Así es como utilicé ControllerContext para pasar una ruta de aplicación falsa:

[TestClass]
public class ClassTest
{
    private Mock<ControllerContext> mockControllerContext;
    private HomeController sut;

    [TestInitialize]
    public void TestInitialize()
    {
        mockControllerContext = new Mock<ControllerContext>();
        sut = new HomeController();
    }
    [TestCleanup]
    public void TestCleanup()
    {
        sut.Dispose();
        mockControllerContext = null;
    }
    [TestMethod]
    public void Index_Should_Return_Default_View()
    {

        // Expectations
        mockControllerContext.SetupGet(x => x.HttpContext.Request.ApplicationPath)
            .Returns("/foo.com");
        sut.ControllerContext = mockControllerContext.Object;

        // Act
        var failure = sut.Index();

        // Assert
        Assert.IsInstanceOfType(failure, typeof(ViewResult), "Index() did not return expected ViewResult.");
    }
}
Xolartek
fuente
1
¿Por qué necesita pasar una ruta de aplicación falsa?
the_law
El código MVC lo ejecutará y lanzará una excepción nula si no está allí.
Joshua Ramirez