Mock HttpContext.Current no método Test Init

Eu estou tentando adicionar testes de unidade para um aplicativo asp.net MVC que eu construí. Nos testes da minha unidade eu uso o seguinte código:

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

Com os seguintes ajudantes para zombar do contexto do 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 class de teste é herdada de uma class base que possui o seguinte:

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

Dentro desse método, ele chama uma biblioteca (da qual não tenho controle) que tenta executar o seguinte código:

 HttpContext.Current.User.Identity.IsAuthenticated 

Agora você provavelmente pode ver o problema. Eu configurei o HttpContext falso contra o controlador, mas não neste método Init base. O teste / zombaria da unidade é muito novo para mim, por isso quero ter certeza de que estou certo. Qual é a maneira correta para eu zombar do HttpContext para que ele seja compartilhado através do meu controlador e quaisquer bibliotecas que são chamadas no meu método de boot.

HttpContext.Current retorna uma instância de System.Web.HttpContext , que não estende System.Web.HttpContextBase . HttpContextBase foi adicionado posteriormente para tratar o HttpContext sendo difícil de burlar. As duas classs são basicamente não relacionadas ( HttpContextWrapper é usado como um adaptador entre elas).

Felizmente, o próprio HttpContext é fakeable apenas o suficiente para você replace o IPrincipal (User) e IIdentity .

O código a seguir é executado conforme o esperado, mesmo em um aplicativo de console:

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

Abaixo do teste, o Init também fará o trabalho.

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

Eu sei que este é um assunto mais antigo, no entanto Mocking um aplicativo MVC para testes de unidade é algo que fazemos regularmente.

Eu só queria adicionar minhas experiências Mocking um aplicativo MVC 3 usando Moq 4 após a atualização para o Visual Studio 2013. Nenhum dos testes de unidade estavam trabalhando no modo de debugging e o HttpContext estava mostrando “não foi possível avaliar a expressão” ao tentar espiar as variables .

Acontece que o visual studio 2013 tem problemas para avaliar alguns objects. Para fazer com que a debugging de aplicativos da web ridicularizados funcionasse novamente, tive que verificar o “Usar modo de compatibilidade gerenciado” em Ferramentas => Opções => Depuração => Configurações gerais.

Eu geralmente faço algo assim:

 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 o contexto como este

 FakeHttpContext.SetFakeContext(moController); 

E chamando o método no controlador para a frente

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

Se o seu aplicativo de terceiros redirect internamente, é melhor simular o HttpContext abaixo:

 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" } };