2011-03-28 20 views
11

He visto muchas discusiones en torno a HttpSessionState y asp.net MVC. Estoy tratando de escribir pruebas para una aplicación asp.net y me pregunto si es posible burlarse de HttpSessionState y, de ser así, ¿cómo?Burlarse de HttpSessionState en ASP.net para pruebas de nunit

Actualmente estoy usando burla de Rhino y Nunit

+0

Si estás hablando de formularios web, se trata de un duplicado de http://stackoverflow.com/questions/1981426/how-do-i-mock-fake-the-s ession-object-in-asp-net-web-forms – PHeiberg

Respuesta

1

mira en las clases HttpSessionStateBase y HttpSessionStateWrapper en System.Web.Abstractions. HttpSessionStateBase es la clase abstracta de la cual HttpSessionState hereda, y HttpSessionStateWrapper se utiliza para envolver una clase sellada en una clase abstracta, que luego puede simular en sus pruebas.

Muchas de las clases System.Web están selladas (por ejemplo, HttpSessionState), por lo que es un verdadero dolor para probar el código cuando tiene métodos y clases que interactúan con ellos. Un patrón que me gusta usar para evitar esto se parece a lo siguiente:

public void DoSomething(HttpSessionState state) 
{ 
    // take this HttpSeassionState and create an abstract HttpSessionStateBase 
    // instance 
    DoSomething(new HttpSessionStateWrapper(state)); 
} 

internal void DoSomething(HttpSessionStateBase state) 
{ 
    // my actual logic for working with the session state 
} 

El método público es difícil de probar, porque HttpSessionState está sellado, y no puede burlarse de ella. Sin embargo, el método interno funciona en una instancia HttpSessionStateBase, que puede simulacro. Tenga en cuenta que lo he marcado como interno porque no quiero que el mundo externo pueda acceder a ese método. Sin embargo, yo hago quieren mis pruebas para poder acceder a esa, así que voy a modificar mis AssemblyInfo.cs incluir algo como esto:

[assembly: InternalsVisibleTo("Vendor.Utilities.Tests")] 

Por último, mi prueba para esto sería algo como esto:

[Test] 
public void Test_DoSomething() 
{ 
    HttpSessionStateBase state = MockRepository.PartialMock<HttpSessionStateBase>(); 
    state.Expect(s => ...); 

    MyClass.DoSomething(state); 

    state.VerifyAllExpectations(); 
} 

Espero que ayude. ¡Buena suerte!

11

Gilbert,

Tal vez soy demasiado tarde para ti. Estoy usando MSpec, pero creo que los conceptos son similares. Necesitaba burlarme de varios componentes del HttpContext en los controladores bajo prueba.

Comencé con estas clases para simular los componentes necesarios (para mis propósitos) en la HttpContextBase. Sobreescribí solo las piezas necesarias dentro de las clases. Sus necesidades variarán en cuanto a los simulacros que necesita en el controlador. Es bastante fácil agregar burlas según sea necesario una vez que comprenda el patrón.

public class MockHttpContext : HttpContextBase 
{ 

    private readonly HttpRequestBase _request = new MockHttpRequest(); 
    private readonly HttpServerUtilityBase _server = new MockHttpServerUtilityBase(); 
    private HttpSessionStateBase _session = new MockHttpSession(); 

    public override HttpRequestBase Request 
    { 
     get { return _request; } 
    } 
    public override HttpServerUtilityBase Server 
    { 
     get { return _server; } 
    } 
    public override HttpSessionStateBase Session 
    { 
     get { return _session; } 
    } 
} 

public class MockHttpRequest : HttpRequestBase 
{ 
    private Uri _url = new Uri("http://www.mockrequest.moc/Controller/Action"); 

    public override Uri Url 
    { 
     get { return _url; } 
    } 
} 

public class MockHttpServerUtilityBase : HttpServerUtilityBase 
{ 
    public override string UrlEncode(string s) 
    { 
     //return base.UrlEncode(s);  
     return s;  // Not doing anything (this is just a Mock) 
    } 
} 


public class MockHttpSession : HttpSessionStateBase 
{ 
    // Started with sample http://stackoverflow.com/questions/524457/how-do-you-mock-the-session-object-collection-using-moq 
    // from http://stackoverflow.com/users/81730/ronnblack 

    System.Collections.Generic.Dictionary<string, object> _sessionStorage = new System.Collections.Generic.Dictionary<string,object>(); 
    public override object this[string name] 
    { 
     get { return _sessionStorage[name]; } 
     set { _sessionStorage[name] = value; } 
    } 

    public override void Add(string name, object value) 
    { 
     _sessionStorage[name] = value; 
    } 
} 

Así es como configuré el contexto del controlador para usar los simulacros (MSpec). Esta es la configuración de las pruebas reales en el controlador (las pruebas se derivan de esta clase)

public abstract class BlahBlahControllerContext 
{ 
    protected static BlahBlahController controller; 

    Establish context =() => 
    { 
     controller = new BlahBlahController(); 
     controller.ControllerContext = new ControllerContext() 
     { 
      Controller = controller, 
      RequestContext = new RequestContext(new MockHttpContext(), new RouteData()), 
     }; 
    }; 
} 

Para ilustrar mejor aquí es una prueba (Especificación de MSpec mundo) que utiliza el simulacro de sesión:

[Subject("ACCOUNT: Retrieve Password")] 
public class retrieve_password_displays_retrieve_password2_page_on_success : BlahBlahControllerContext 
{ 
    static ActionResult result; 
    static RetrievePasswordModel model; 

    Establish context =() => 
    { 
     model = new RetrievePasswordModel() 
     { 
      UserName = "Mike" 
     }; 
    }; 

    Because of =() => 
    { 
     result = controller.RetrievePassword(model); 
    }; 

    It should_return_a_RedirectToRouteResult =() => 
    { 
     result.is_a_redirect_to_route_and().action_name().ShouldEqual("RetrievePassword2"); 
    }; 

    It session_should_contain_UN_value =() => 
    { 
     controller.HttpContext.Session["UN"].ShouldEqual("Mike"); 
    }; 

    It session_should_contain_PQ_value =() => 
    { 
     controller.HttpContext.Session["PQ"].ShouldEqual("Question"); 
    }; 
} 

Me doy cuenta de que esto no usa Rhino Mocks. Espero que ilustre los principios y que los lectores puedan adoptarlo con sus herramientas y métodos específicos.

7

Si necesita instanciar exactamente HttpSessionState para pruebas de código heredado, puede aprovechar el mecanismo de FormatterServices para obtener un objeto no inicializado.Para que funcione se necesita para establecer el campo _container privada aunque, como en el constructor interna

Ejemplo:

var state = (HttpSessionState) System.Runtime.Serialization 
    .FormatterServices.GetUninitializedObject(typeof(HttpSessionState)); 

var containerFld = typeof(HttpSessionState).GetField(
    "_container", BindingFlags.Instance | BindingFlags.NonPublic); 

var itemCollection = new SessionStateItemCollection(); 
itemCollection["element"] = 1; 

containerFld.SetValue(
    state, 
    new HttpSessionStateContainer(
     "1", 
     itemCollection, 
     new HttpStaticObjectsCollection(), 
     900, 
     true, 
     HttpCookieMode.UseCookies, 
     SessionStateMode.InProc, 
     false 
    ) 
); 
+0

Esto hizo mi día. Exactamente para lo que yo personalmente lo necesitaba y funciona. GRACIAS. – Bokonon

+0

Impresionante. Me salvaste el día (y) – Erwin

0

Esto es lo que hice a la contribución sobre la base de los demás ...

clase pública MockWebContext {

public Mock<RequestContext> RoutingRequestContext { get; private set; } 
    public Mock<HttpContextBase> Http { get; private set; } 
    public Mock<HttpServerUtilityBase> Server { get; private set; } 
    public Mock<HttpResponseBase> Response { get; private set; } 
    public Mock<HttpRequestBase> Request { get; private set; } 
    public Mock<HttpSessionStateBase> Session { get; private set; } 
    public Mock<ActionExecutingContext> ActionExecuting { get; private set; } 
    public HttpCookieCollection Cookies { get; private set; } 

    private IDictionary items; 

    public MockWebContext() 
    { 
     RoutingRequestContext = new Mock<RequestContext>(MockBehavior.Loose); 
     ActionExecuting = new Mock<ActionExecutingContext>(MockBehavior.Loose); 
     Http = new Mock<HttpContextBase>(MockBehavior.Loose); 
     Server = new Mock<HttpServerUtilityBase>(MockBehavior.Loose); 
     Response = new Mock<HttpResponseBase>(MockBehavior.Loose); 
     Request = new Mock<HttpRequestBase>(MockBehavior.Loose); 
     Session = new Mock<HttpSessionStateBase>(MockBehavior.Loose); 
     Cookies = new HttpCookieCollection(); 

     items = new Dictionary<string, object>(); 

     RoutingRequestContext.SetupGet(c => c.HttpContext).Returns(Http.Object); 
     ActionExecuting.SetupGet(c => c.HttpContext).Returns(Http.Object); 
     Http.SetupGet(c => c.Request).Returns(Request.Object); 
     Http.SetupGet(c => c.Response).Returns(Response.Object); 
     Http.SetupGet(c => c.Server).Returns(Server.Object); 
     Http.SetupGet(c => c.Session).Returns(Session.Object); 
     Http.SetupGet(c => c.Items).Returns(items); 
     Request.Setup(c => c.Cookies).Returns(Cookies); 
     Request.Setup(c => c.RequestContext).Returns(RoutingRequestContext.Object); 
     Response.Setup(c => c.Cookies).Returns(Cookies); 
     Session.Setup(c => 
      c.Add(It.IsAny<string>(), It.IsAny<object>())     
      ).Callback((string key, object value)=> items.Add(key, value)); 

     Session.Setup(c => 
      c.Remove(It.IsAny<string>()) 
     ).Callback((string key) => items.Remove(key)); 


     Session.Setup(c => 
      c.Clear() 
     ).Callback(() => items.Clear()); 

     Session.Setup(c => 
     c[It.IsAny<string>()] 
     ).Returns((string key)=> items[key]); 


    } 

} 
Cuestiones relacionadas