Come faccio a deridere HttpContext in 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).
    ...
 }

il mio controller di base ha un override di Initialize che ottiene questo requestContext. Sto cercando di trasmetterlo ma non sto facendo qualcosa di giusto.

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

Dove posso ottenere ulteriori informazioni sul mocking di RequestContext e HttpContext utilizzando Moq? Sto cercando di deridere i cookie e il contesto generale.

Risposte:


61

HttpContext è di sola lettura, ma in realtà è derivato da ControllerContext, che è possibile impostare.

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

Questo ha funzionato per me permettendomi di impostare un HttpContext fittizio sul controller.
Joel Malone

39

Crea una richiesta, una risposta e inseriscili entrambi in HttpContext:

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

La domanda riguarda le classi * Base, cioè HttpRequestBase, non HttpRequest - non sono sicuro del motivo per cui entrambe sono necessarie io stesso e ancora più fastidioso che siano "sigillate". Nessun modo per impostare LogonUserIdentity :(
Chris Kimpton

Se hanno effettuato il marshalling del mio riferimento, è ancora possibile tramite il telecomando, quindi non dovrebbe essere un problema.
0100110010101

1
@ChrisKimpton: come ultima risorsa, c'è sempre una riflessione ;-)
Oliver

Funziona quando lo si collega al controller, in questo modo: controller.ControllerContext = new ControllerContext (new HttpContextWrapper (httpContextMock), new RouteData (), controller);
Andreas Vendel

sì. puoi infatti impostare .LogonUserIdentity - _request.Setup (n => n.LogonUserIdentity) .Returns ((WindowsIdentity.GetCurrent));
KevinDeus

12

Grazie utente 0100110010101.

Ha funzionato per me e qui ho avuto un problema durante la scrittura del testcase per il codice seguente:

 var currentUrl = Request.Url.AbsoluteUri;

Ed ecco le righe che hanno risolto il 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);

Potrebbe essere utile per gli altri.


Non riesco a usare il tipo HttpRequest - è qualcos'altro adesso?
Vincent Buscarello

1
Questo non è utile perché tutti i campi in HttpRequest sono immutabili
A br

6

Ecco un esempio di come puoi impostarlo: Mocking HttpContext HttpRequest e HttpResponse per UnitTests (usando Moq)

Nota i metodi di estensione che aiutano davvero a semplificare l'uso di queste classi beffarde:

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

Ecco un esempio di come scrivere uno Unit Test utilizzando moq per verificare che un HttpModule funzioni come previsto: Unit Test for HttpModule using Moq to wrap HttpRequest

Aggiornamento: questa API è stata riformattata in


I collegamenti sono interrotti - includi il codice nella risposta
Ade

5

Ecco come ho usato ControllerContext per passare un falso percorso dell'applicazione:

[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
Perché hai bisogno di passare un falso percorso dell'applicazione?
the_law

Il codice MVC lo eseguirà e genererà un'eccezione nulla se non è presente.
Joshua Ramirez
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.