Mock HttpContext.Current en el método Test Init

Intento agregar pruebas unitarias a una aplicación ASP.NET MVC que he creado. En mis pruebas unitarias utilizo el siguiente código:

[TestMethod] public void IndexAction_Should_Return_View() { var controller = new MembershipController(); controller.SetFakeControllerContext("TestUser"); ... } 

Con los siguientes ayudantes para simular el contexto del controlador:

 public static class FakeControllerContext { public static HttpContextBase FakeHttpContext(string username) { var context = new Mock(); context.SetupGet(ctx => ctx.Request.IsAuthenticated).Returns(!string.IsNullOrEmpty(username)); if (!string.IsNullOrEmpty(username)) context.SetupGet(ctx => ctx.User.Identity).Returns(FakeIdentity.CreateIdentity(username)); return context.Object; } public static void SetFakeControllerContext(this Controller controller, string username = null) { var httpContext = FakeHttpContext(username); var context = new ControllerContext(new RequestContext(httpContext, new RouteData()), controller); controller.ControllerContext = context; } } 

Esta clase de prueba hereda de una clase base que tiene lo siguiente:

 [TestInitialize] public void Init() { ... } 

Dentro de este método llama a una biblioteca (que no tengo control) que intenta ejecutar el siguiente código:

 HttpContext.Current.User.Identity.IsAuthenticated 

Ahora probablemente puedas ver el problema. He configurado el falso HttpContext contra el controlador pero no en este método básico de Init. Las pruebas / burlas unitarias son muy nuevas para mí, así que quiero asegurarme de que lo entiendo bien. ¿Cuál es la forma correcta para mí de simular el HttpContext para que se comparta a través de mi controlador y las bibliotecas a las que se llama en mi método Init?

HttpContext.Current devuelve una instancia de System.Web.HttpContext , que no extiende System.Web.HttpContextBase . HttpContextBase se agregó más tarde para hacer que HttpContext sea ​​difícil de simular. Las dos clases básicamente no están relacionadas ( HttpContextWrapper se usa como un adaptador entre ellas).

Afortunadamente, HttpContext es falso solo lo suficiente para reemplazar el IPrincipal (Usuario) y IIdentity .

El siguiente código se ejecuta como se espera, incluso en una aplicación de consola:

 HttpContext.Current = new HttpContext( new HttpRequest("", "http://tempuri.org", ""), new HttpResponse(new StringWriter()) ); // User is logged in HttpContext.Current.User = new GenericPrincipal( new GenericIdentity("username"), new string[0] ); // User is logged out HttpContext.Current.User = new GenericPrincipal( new GenericIdentity(String.Empty), new string[0] ); 

Debajo de Test Init también hará el trabajo.

 [TestInitialize] public void TestInit() { HttpContext.Current = new HttpContext(new HttpRequest(null, "http://tempuri.org", null), new HttpResponse(null)); YourControllerToBeTestedController = GetYourToBeTestedController(); } 

Sé que este es un tema más antiguo, sin embargo, Mocking a MVC para pruebas unitarias es algo que hacemos con mucha frecuencia.

Solo quería agregar mis experiencias Mocking a MVC 3 usando Moq 4 después de actualizar a Visual Studio 2013. Ninguna de las pruebas de unidad funcionaba en modo de depuración y HttpContext mostraba “could not evaluate expression” cuando intentaba ver las variables .

Resulta que Visual Studio 2013 tiene problemas para evaluar algunos objetos. Para que la depuración de aplicaciones web falsas volviera a funcionar, tuve que verificar el “Uso del modo de compatibilidad administrada” en Herramientas => Opciones => Depuración => Configuración general.

Generalmente hago algo como esto:

 public static class FakeHttpContext { public static void SetFakeContext(this Controller controller) { var httpContext = MakeFakeContext(); ControllerContext context = new ControllerContext( new RequestContext(httpContext, new RouteData()), controller); controller.ControllerContext = context; } private static HttpContextBase MakeFakeContext() { var context = new Mock(); var request = new Mock(); var response = new Mock(); var session = new Mock(); var server = new Mock(); var user = new Mock(); var identity = new Mock(); context.Setup(c=> c.Request).Returns(request.Object); context.Setup(c=> c.Response).Returns(response.Object); context.Setup(c=> c.Session).Returns(session.Object); context.Setup(c=> c.Server).Returns(server.Object); context.Setup(c=> c.User).Returns(user.Object); user.Setup(c=> c.Identity).Returns(identity.Object); identity.Setup(i => i.IsAuthenticated).Returns(true); identity.Setup(i => i.Name).Returns("admin"); return context.Object; } } 

E iniciando el contexto de esta manera

 FakeHttpContext.SetFakeContext(moController); 

Y llamando al Método en el controlador directo

 long lReportStatusID = -1; var result = moController.CancelReport(lReportStatusID); 

Si la aplicación de terceros redirecciona internamente, entonces es mejor burlarse de HttpContext de la siguiente manera:

 HttpWorkerRequest initWorkerRequest = new SimpleWorkerRequest("","","","",new StringWriter(CultureInfo.InvariantCulture)); System.Web.HttpContext.Current = new HttpContext(initWorkerRequest); System.Web.HttpContext.Current.Request.Browser = new HttpBrowserCapabilities(); System.Web.HttpContext.Current.Request.Browser.Capabilities = new Dictionary { { "requiresPostRedirectionHandling", "false" } };