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.

Geo
quelle

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 );
Tvanfosson
quelle
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);
0100110010101
quelle
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.

Chandan Kumar
quelle
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

Dinis Cruz
quelle
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.");
    }
}
Xolartek
quelle
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