Pregunta

Tengo un dispositivo de prueba de unidad en el que intento probar una ControllerAction en un controlador ASP.NET MVC que se utiliza para funciones de membresía en una aplicación web. Estoy tratando de burlarme del HttpContext para las pruebas. ControllerAction bajo prueba en realidad establece propiedades en HttpContext, como valores de sesión, valores de Response.Cookies, etc. Esto no es todo el código, pero aquí hay una muestra aproximada de la prueba que estoy tratando de ejecutar :

[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?
}

No estoy seguro de lo que estoy haciendo mal, pero me encantaría que alguien pudiera señalarme en la dirección correcta y mostrarme cómo configurar este objeto HttpContextBase simulado para que mi controlador pueda establecer valores en sus propiedades, y Puedo hacer afirmaciones sobre esas propiedades para asegurarme de que mi ControllerAction esté haciendo lo que necesito.

¿Me estoy acercando a esto de la manera incorrecta? Sé que los Controladores MVC tienen un ControllerContext que puedo usar para establecer valores para la Sesión, etc., pero no puedo entender cómo se podría burlar algo así sin inyectarlo. ¿Hay alguna forma de hacerlo en su lugar? (También necesito poder pasar el contexto a mi MembershipProvider también) ¿Sería un mejor enfoque?

Gracias.

¿Fue útil?

Solución

Estoy usando una versión de algún código que Steve Sanderson incluyó en su Pro Asp.NET MVC book ... y actualmente tengo un dilema moral sobre si está bien publicar el código aquí. ¿Qué tal si me comprometo con una versión muy simplificada? ;)

Para que esto se pueda reutilizar fácilmente, cree una clase similar a la siguiente en la que pasará su controlador. Esto configurará tus simulacros y los configurará en el ControllerContext de tu controlador

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

Y luego, en su método de prueba, simplemente crearía una instancia de ContextMocks y pasaría el objeto controlador que está probando:

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

Parece muy similar a los ejemplos de Craig, pero esto es con Moq v3. Tengo que darle mi apoyo a Steve Sanderson para esto: lo estoy usando como base para probar todo tipo de cosas que de otro modo serían difíciles de probar: cookies, sesión, método de solicitud, cadena de consulta y más.

Otros consejos

Así es como lo hago .

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

Esta es una versión mejorada de la biblioteca MvcMockHelpers lanzada por Scott Hanselman . Este es el código Moq 2.0; la sintaxis es ligeramente diferente en 3.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top