Como faço para simular o HttpContext na 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).
    ...
 }

meu controlador de base tem uma substituição do Initialize que obtém este requestContext. Estou tentando passar isso adiante, mas não estou fazendo algo certo.

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

Onde posso obter mais informações sobre como simular meu RequestContext e HttpContext usando o Moq? Estou tentando simular cookies e o contexto geral.

Respostas:


61

HttpContext é somente leitura, mas, na verdade, é derivado do ControllerContext, que você pode definir.

 controller.ControllerContext = new ControllerContext( context.Object, new RouteData(), controller );

Este funcionou para mim, permitindo-me definir um HttpContext fictício no controlador.
Joel Malone

39

Crie uma solicitação, uma resposta e coloque ambas em HttpContext:

HttpRequest httpRequest = new HttpRequest("", "http://mySomething/", "");
StringWriter stringWriter = new StringWriter();
HttpResponse httpResponse = new HttpResponse(stringWriter);
HttpContext httpContextMock = new HttpContext(httpRequest, httpResponse);

A questão é sobre as classes * Base, ou seja, HttpRequestBase, não HttpRequest - não tenho certeza de por que ambas são necessárias e, mais irritante ainda, são "seladas". Não é possível definir LogonUserIdentity :(
Chris Kimpton,

Se eles forem encaminhados para minha referência, ainda é possível via remoting, então não deve ser um problema.
0100110010101

1
@ChrisKimpton: Como último recurso, sempre há reflexão ;-)
Oliver

Isso funciona ao anexá-lo ao controlador, assim: controlador.ControllerContext = new ControllerContext (new HttpContextWrapper (httpContextMock), new RouteData (), controlador);
Andreas Vendel

sim. você realmente pode definir .LogonUserIdentity - _request.Setup (n => n.LogonUserIdentity) .Returns ((WindowsIdentity.GetCurrent));
KevinDeus de

12

Obrigado, usuário 0100110010101.

Funcionou para mim e aqui eu tive um problema ao escrever o caso de teste para o código abaixo:

 var currentUrl = Request.Url.AbsoluteUri;

E aqui estão as linhas que resolveram o 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);

Pode ser útil para os outros.


Não consigo usar o tipo HttpRequest - é outra coisa agora?
Vincent Buscarello

1
Isso não é útil porque todos os campos em HttpRequest são imutáveis
A br

6

Aqui está um exemplo de como você pode configurar isso: Mocking HttpContext HttpRequest e HttpResponse para UnitTests (usando Moq)

Observe os métodos de extensão que realmente ajudam a simplificar o uso dessas classes de simulação:

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

Aqui está um exemplo de como escrever um Teste de Unidade usando moq para verificar se um HttpModule está funcionando conforme o esperado: Teste de Unidade para HttpModule usando Moq para envolver HttpRequest

Update: esta API foi refatorada para


Links quebrados - inclua o código em sua resposta
Hades

5

Veja como usei o ControllerContext para passar um caminho de aplicativo falso:

[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.");
    }
}

1
Por que você precisa passar um caminho de aplicativo falso?
the_law

O código MVC irá executá-lo e lançar uma exceção nula se não estiver lá.
Joshua Ramirez
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.