Thursday, October 28, 2010

Unit Testing - Mocking the Session State in MVC Using Moq

I was working on a unit test this week that required me to mock the session state. I had done this before elsewhere using Moq, but I ran into a problem. Moq is unable to stub the sessions getter and setter. So, if you have a method that writes something to the session, you will be unable to return it using Moq. I found some code online from this stackoverflow post


public class MockHttpSession : HttpSessionStateBase
{
    Dictionary<string, object> m_SessionStorage = new Dictionary<string, object>();

    public override object this[string name]
    {
        get { return m_SessionStorage[name]; }
        set { m_SessionStorage[name] = value; }
    }
}


However, I quickly ran into some problems with it. Can you spot what the problem with this code is? It doesn't handle keys that don't exist! With session, you can use a key that doesn't exist and the session will return null. Using the code above with a dictionary, you will get an exception if you try to access a key that doesn't exist.

There is also a second problem with this code! If I did the following

Session.Add("MyKey", "This is my Key");

and "MyKey" already existed, an exception would be thrown, because the key already existed. So we need to work around both of these problems. Here is some code that addresses both issues

public class MockHttpSession : HttpSessionStateBase
{
    Dictionary<string, object> m_SessionStorage = new Dictionary<string, object>();

    public override object this[string name]
    {
        get
        {
            if (m_SessionStorage.ContainsKey(name))
                return m_SessionStorage[name];

            return null;
        }
        set { m_SessionStorage[name] = value; }
    }

    public override void Add(string name, object value)
    {
        if (m_SessionStorage.ContainsKey(name))
            m_SessionStorage[name] = value;
        else
            m_SessionStorage.Add(name,value);
    }
} 

You can use this method anytime you need to set a value in the session in the method you are testing, and you
don't want that value to be mocked. In my case, I needed to ensure that the correct values were being set as part of the unit test.

2 comments:

  1. Real ASP.NET MVC programmers don't NEED session states. We just give the server the stink eye and it remembers.

    -- Not Kelly

    ReplyDelete
  2. I completely disagree with you:

    1) Faster than light travel IS possible, you just have to have Chuck Norris teach you how to achieve this velocity

    2) Lightsabers exist, they are stored in a government bunker so that I cannot get to them, because I got my hands on a lightsaber I would become the most powerful sith in the galaxy

    3) The asgard are awesome. They are little gray beings that talk with an awesome accent and should be respected

    so, in closing:

    Nice post

    ReplyDelete