Wie verspotte ich den HttpContext in ASP.NET MVC mit 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).
    ...
 }

Mein Basis-Controller hat eine Überschreibung der Initialisierung, die diesen requestContext erhält. Ich versuche das weiterzugeben, aber ich mache etwas nicht richtig.

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

Wo kann ich weitere Informationen zum Verspotten meines RequestContext und HttpContext mit Moq erhalten? Ich versuche, Cookies und den allgemeinen Kontext zu verspotten.

Antworten:


61

HttpContext ist schreibgeschützt, wird jedoch tatsächlich vom ControllerContext abgeleitet, den Sie festlegen können.

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

Dieser hat für mich funktioniert, indem ich einen nachgebildeten HttpContext auf dem Controller festlegen konnte.
Joel Malone

38

Erstellen Sie eine Anfrage, eine Antwort und fügen Sie beide in HttpContext ein:

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

Die Frage bezieht sich auf die * Basisklassen, dh HttpRequestBase, nicht HttpRequest - nicht sicher, warum beide selbst benötigt werden und noch ärgerlicher, dass sie "versiegelt" sind. Keine Möglichkeit, LogonUserIdentity festzulegen :(
Chris Kimpton

Wenn sie meine Referenz zusammenstellen, ist dies immer noch per Remoting möglich, daher sollte dies kein Problem sein.
0100110010101

1
@ ChrisKimpton: Als letztes Mittel gibt es immer Reflexion ;-)
Oliver

Dies funktioniert beim Anhängen an den Controller wie folgt: controller.ControllerContext = neuer ControllerContext (neuer HttpContextWrapper (httpContextMock), neuer RouteData (), Controller);
Andreas Vendel

Ja. Sie können tatsächlich .LogonUserIdentity festlegen - _request.Setup (n => n.LogonUserIdentity) .Returns ((WindowsIdentity.GetCurrent));
KevinDeus

12

Vielen Dank Benutzer 0100110010101.

Es hat bei mir funktioniert und hier hatte ich ein Problem beim Schreiben des Testfalls für den folgenden Code:

 var currentUrl = Request.Url.AbsoluteUri;

Und hier sind die Zeilen, die das Problem gelöst haben

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

Könnte für die anderen hilfreich sein.


Ich kann den Typ HttpRequest anscheinend nicht verwenden - ist das jetzt etwas anderes?
Vincent Buscarello

1
Dies ist nicht nützlich, da alle Felder in HttpRequest unveränderlich sind
A br

6

Hier ist ein Beispiel, wie Sie dies einrichten können: Verspotten von HttpContext HttpRequest und HttpResponse für UnitTests (mit Moq)

Beachten Sie die Erweiterungsmethoden, die wirklich dazu beitragen, die Verwendung dieser Spottklassen zu vereinfachen:

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

Hier ist ein Beispiel, wie Sie einen Unit-Test mit moq schreiben, um zu überprüfen, ob ein HttpModule wie erwartet funktioniert: Unit-Test für HttpModule mit Moq zum Umschließen von HttpRequest

Update: Diese API wurde überarbeitet


Links sind defekt - bitte geben Sie den Code in Ihre Antwort ein
Hades

5

So habe ich den ControllerContext verwendet, um einen gefälschten Anwendungspfad zu übergeben:

[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
Warum mussten Sie einen gefälschten Anwendungspfad übergeben?
the_law

Der MVC-Code führt ihn aus und löst eine Null-Ausnahme aus, wenn er nicht vorhanden ist.
Joshua Ramirez
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.