Verspotten von HttpContextBase mit Moq

Ich habe eine Komponentenprüfvorrichtung, in der ich versuche, eine ControllerAction auf einem ASP.NET MVC-Controller zu testen, der für Mitgliedschaftsfunktionen in einer Web-App verwendet wird. Ich versuche, den HttpContext für die Tests zu verspotten. Die getestete ControllerAction legt tatsächlich Eigenschaften für den HttpContext fest, z. B. Sitzungswerte, Response.Cookies-Werte usw. Dies ist nicht der ganze Code, aber hier ist ein grobes Beispiel des Tests, den ich zu laufen versuche:

[Test]
public void ValidRegistrationDataSuccessfullyCreatesAndRegistersUser()
{
    var context = new Mock<HttpContextBase>() {DefaultValue = DefaultValue.Mock};
    context.SetupAllProperties();
    var provider = new Mock<MembershipProvider>(new object[] {context.Object});
    var controller = new AccountController(context.Object, provider.Object);
    // This just sets up a local FormCollection object with valid user data 
    // in it to use to attempt the registration
    InitializeValidFormData();
    ActionResult result = controller.Register(_registrationData);
    Assert.IsInstanceOfType(typeof(ViewResult), result);
    // Here is where I'd like to attempt to do Assertions against properties 
    // of the HttpContext, like ensuring that a Session object called "User" 
    // exists, and new auth cookie exists on the Response.Cookies collection. 
    // So far I've been unable to successfully check the values of those properties.
    // I've been unsuccessful in getting those properties setup correctly on my 
    // mock object so that my ControllerAction can actually *set* their values, 
    // and that I can make assertions on them afterwards. The above code actually
    // generates a StackOverflowException (which I've reported) on the
    // context.SetupAllProperties() call. What am I doing wrong, or what do I need 
    // to do to be able to set and assert on those context properties?
}

Nicht sicher, was ich falsch mache, aber ich würde es lieben, wenn jemand mich in die richtige Richtung weisen und mir zeigen könnte, wie man dieses Mock-HttpContextBase-Objekt so einrichtet, dass mein Controller tatsächlich Werte für seine Eigenschaften festlegen kann. , und ich kann Assertionen zu diesen Eigenschaften erstellen, um sicherzustellen, dass meine ControllerAction das tut, was ich brauche.

Nähere ich das falsch? Ich weiß, dass MVC-Controller über einen ControllerContext verfügen, mit dem ich Werte für Session usw. festlegen kann, aber ich kann nicht herausfinden, wie so etwas verspottet werden könnte, ohne es zu injizieren. Gibt es stattdessen eine Möglichkeit, dies zu tun? (Ich muss auch in der Lage sein, den Kontext an meinen MembershipProvider weiterzugeben) Wäre das ein besserer Ansatz?

Danke.

Antwort auf "Verspotten von HttpContextBase mit Moq " 2 von antworten

Here's how I do it. .

    public static HttpContextBase FakeHttpContext()
    {
        var context = new Mock<HttpContextBase>();
        var request = new Mock<HttpRequestBase>();
        var response = new Mock<HttpResponseBase>();
        var session = new Mock<HttpSessionStateBase>();
        var server = new Mock<HttpServerUtilityBase>();
        var user = new Mock<IPrincipal>();
        var identity = new Mock<IIdentity>();

        request.Expect(req => req.ApplicationPath).Returns("~/");
        request.Expect(req => req.AppRelativeCurrentExecutionFilePath).Returns("~/");
        request.Expect(req => req.PathInfo).Returns(string.Empty);
        response.Expect(res => res.ApplyAppPathModifier(It.IsAny<string>()))
            .Returns((string virtualPath) => virtualPath);
        user.Expect(usr => usr.Identity).Returns(identity.Object);
        identity.ExpectGet(ident => ident.IsAuthenticated).Returns(true);

        context.Expect(ctx => ctx.Request).Returns(request.Object);
        context.Expect(ctx => ctx.Response).Returns(response.Object);
        context.Expect(ctx => ctx.Session).Returns(session.Object);
        context.Expect(ctx => ctx.Server).Returns(server.Object);
        context.Expect(ctx => ctx.User).Returns(user.Object);

        return context.Object;
    }

Dies ist eine verbesserte Version von the MvcMockHelpers library released by Scott Hanselman. This is Moq 2.0 code; the syntax is slightly different in 3. . Dies ist Moq 2.0-Code; Die Syntax unterscheidet sich in 3.

Ich verwende eine Version von einige Misbuch Steve Sanderson in seinem Pro Asp.NET MVC book... and I'm currently having a moral dilemma whether it's okay to post the code here. How about I compromise with a highly stripped down version? ;) enthalten ... und ich habe derzeit ein moralisches Dilemma, ob es in Ordnung ist, den Code hier zu posten. Wie wäre es mit einer stark abgespeckten Version? ;)

So kann dies leicht wiederverwendet werden, erstellen Sie eine Klasse ähnlich der unten, dass Sie Ihren Controller übergeben. Dies wird Ihre Mocks einrichten und sie auf den ControllerContext Ihres Controllers

public class ContextMocks
{
    public Moq.Mock<HttpContextBase> HttpContext { get; set; }
    public Moq.Mock<HttpRequestBase> Request { get; set; }
    public RouteData RouteData { get; set; }

    public ContextMocks(Controller controller)
    {
        //define context objects
        HttpContext = new Moq.Mock<HttpContextBase>();
        HttpContext.Setup(x => x.Request).Returns(Request.Object);
        //you would setup Response, Session, etc similarly with either mocks or fakes

        //apply context to controller
        RequestContext rc = new RequestContext(HttpContext.Object, new RouteData());
        controller.ControllerContext = new ControllerContext(rc, controller);
    }
}

setzen Und dann würden Sie in Ihrer Testmethode einfach eine Instanz von ContextMocks erstellen und das Controller-Objekt, das Sie testen, übergeben:

[Test]
Public void test()
{
     var mocks = new ContextMocks(controller);
     var req = controller.Request; 
     //do some asserts on Request object
}

scheint Craigs Beispielen sehr ähnlich zu sein, aber das ist mit Moq v3. Dafür muss ich Steve Sanderson Requisiten geben - ich benütze dies als Grundlage, um alle Arten von ansonsten traditionell schwer zu testenden Sachen zu testen: Cookies, Session, Request-Methode, Querystring und mehr!