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.

Introduction

Hello everyone,

My Name is Aaron, and this is my blog. I created this blog so that I could use it as a tool to share my findings as I explore anything and everything regarding programming on the .Net platform. I currently work for a company full time as a software developer using C# and both Asp.Net and MVC along with browser technologies such as JQuery.


Welcome everyone, and I hope you enjoy the ride