It has been a few years since I have had the chance to explore the latest enhancements to ASP.NET. The development in my day job was locked into traditional ASP.NET forms just before MVC 1.0 was released and there has not been any opportunity to change. TDD, dependency injection and inversion of control containers all slipped by with me staring at them with my nose pressed against the window. I also develop in php with CodeIgniter, so I am quite familiar with the idea of MVC and was thoroughly excited when recently, the company I work for, began brewing the idea for a new project. Now was the time to change, so I stocked up on books and blog articles and began the big catch up. I won’t go on about how great MVC is, especially when I spent many hours battling against the web form paradigm – its such an anti-web way of doing things but with these new ways of working, I now feel a new vigour for .Net web development.
My journey found me working with Moq and although it is pretty self explanatory, most examples and articles are in C# and the documentation for the library is a little sparse. I don’t find the switching between C# and VB.NET very difficult as there is mostly only a syntax difference between them but I did find a problem when, in my unit tests, I needed to assert that entries in the session had been set correctly. So here is how to do it in VB.NET.
Checking a value has been set in Session
The first thing that you need is a session object that you can look at in your tests. It needs to inherit from HttpSessionStateBase and is pretty simple as the session is just a key-value store – we can use a generic dictionary to store the values we want to check:
Public Class HttpSessionMock Inherits HttpSessionStateBase Private ReadOnly objects As New Dictionary(Of String, Object)() Default Public Overloads Overrides Property Item(ByVal name As String) As Object Get Return If((objects.ContainsKey(name)), objects(name), Nothing) End Get Set(ByVal value As Object) objects(name) = value End Set End Property Public Overrides Sub Add(ByVal name As String, ByVal value As Object) objects.Add(name, value) End Sub End Class
So we now have a session store and we can then use Moq to utilise that in our controller during our test. This is done be setting up a controller context:
'Create a real mock session object to check value against Dim session As New HttpSessionMock() 'Create a moq controller context Dim mockcontext As New Mock(Of ControllerContext) 'Ensure our session object is returned when the session is requested mockcontext.SetupGet(Function(c As ControllerContext) c.HttpContext.Session).Returns(session) 'set our controller context to be the moq context MyController.ControllerContext = mockcontext.Object
We can then run our controller action that sets a value in our mock session object and assert that the correct value is set as follows:
'run the controller action Dim result = MyController.SomeAction() 'assert the session contains the object we expect Assert.IsInstanceOfType(session.Item("SessionItemToCheck"), GetType(ExpectedSessionObject)) 'TODO:other tests to ensure session item is correct
Ensuring a value is returned from Session
You can use the above real mock session object to do this in exactly the same way but we can also setup Moq to return a particular value from session directly:
'create a test object/value we want session to return Dim MySessionValue as New SomeObject() 'create our moq controller context Dim mockcontext As New Mock(Of ControllerContext) 'ensure our test object gets returned by the moq session mockcontext.SetupGet(Function(c As ControllerContext) c.HttpContext.Session("SessionItemToTest")).Returns(MySessionValue) 'assign our context to the controller controller.ControllerContext = mockcontext.Object 'TODO: run controller action and assert results
When I look at the code now, I realise that it is quite simple to achieve. However, it took me a little while to get my head around Moq and figure this out as all the examples out there seemed to be trying to do so much more than solely testing session state. It confused me anyhow.