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.