Search code examples
asp.net-mvcunit-testingrhino-mockssession-state

how to unit test session state


I'm trying to figure out how to unit test my object that persists itself to session state.

The controller does something like...

    [HttpPost]
    public ActionResult Update(Account a)
    {
        SessionManager sm = SessionManager.FromSessionState(HttpContext.Current.Session);
        if ( a.equals(sm.Account) )
          sm.Account = a;
        return View("View", a);
    }

And the session manager serializes itself to session state

public class SessionManager
    {
        public static SessionManager FromSessionState(HttpSessionStateBase state)
        {
            return state["sessionmanager"] as SessionManager ?? new SessionManager();
        }

        public Guid Id { get; set; }
        public Account Account { get; set; }
        public BusinessAssociate BusinessAssociate {get; set; }
    }

I'm thinking that there are two approaches to unit testing...

  1. in the static instantiator pass in the session state reference and then restore from that. this would allow me to mock this parameter and everything would be golden.

    public static SessionManager FromSessionState(HttpSessionStateWrapper session) { return session["sessionmanager"] as SessionManager ?? new SessionManager(); }

  2. create a mock for the SessionManager and use that for testing of the controller.


Solution

  • Here's an idea: Create a session manager "persistence" interface:

    public interface ISessionManagerPersist
    {
        SessionManager Load();
        void Save(SessionManager sessionManager);
    }
    

    Create an HTTPSession-based implementation of your persistence:

    public class SessionStatePersist : ISessionManagerPersist
    {
        public SessionManager Load()
        {
            return HttpContext.Current.Session["sessionmanager"] as SessionManager ?? new SessionManager();
        }
    
        public void Save(SessionManager sessionManager)
        {
            HttpContext.Current.Session["sessionmanager"] = sessionManager;
        }
    }
    

    Now make your controller have a dependency on ISessionManagerPersist. You can inject a stub ISessionManagerPersist during testing and use the session-based one during production. This also has the benefit of not needing changes if you decided to persist somewhere else (like a DB or something). Just implement a new ISessionManagerPersist.