views:

413

answers:

4

Is there a way to mock/fake the session object in ASP.Net Web forms when creating unit tests?

I am currenclty storing user details in a session variable which is accessed by my business logic. When testing my business logic, in isolation, the session is not available. This seems to indicate a bad design (though im not sure). Should the business logic layer be accessing session variables in the first place?

If so, then how would I go about swapping the user details with a fake object for testing?

+1  A: 

Your instincts are correct---you shouldn't be accessing pieces of the ASP.NET framework from your business logic. This would include Session.

To answer your first question, you can mock static classes using a product like Typemock Isolator, but you'll be better off if you refactor your code to wrap access to Session in an interface (i.e., IHttpSession.) You can then mock IHttpSession.

Andy Wilson
+4  A: 

In ASP.NET, you can't create a Test Double of HttpSessionState because it is sealed. Yes, this is bad design on the part of the original designers of ASP.NET, but there's not a lot to do about it.

This is one of many reasons why TDD'ers and other SOLID practictioners have largely abandonded ASP.NET in favor of ASP.NET MVC and other, more testable frameworks. In ASP.NET MVC, the HTTP session is modelled by the abstract HttpSessionStateBase class.

You could take a similar approach and let your objects work on an abstract session, and then wrap the real HttpSessionState class when you are running in the ASP.NET environment. Depending on circumstances, you may even be able to reuse the types from System.Web.Abstractions, but if not, you can define your own.

In any case, your business logic is your Domain Model and it should be modeled independently of any particular run-time technology, so I would say that it shouldn't be accessing the session object in the first place.

If you absolutely need to use Test Doubles for unit tets involving HttpSessionState, this is still possible with certain invasive dynamic mocks, such as TypeMock or Moles, althought these carry plenty of disadvantages as well (see this comparison of dynamic mocks).

Mark Seemann
A: 

One approach is to pass a lambda expression to your code that takes a string (or some other object) as input, and uses it to set either the Session object or a test container.

However, as others have said, it's a good idea to move access to the Session object out of your BLL.

RickNZ
+1  A: 

In Asp.Net webforms, you cannot escape the fact that framework's entry into your code comes from aspx pages. I agree that your business layer should not touch the asp.net specific components directly but you have to have a model's storage container and session in asp.net is a good area. Thus, one possible approach is to create ISessionManager for purpose of interacting inside your business layer. Then, implement the concrete type by using HttpSessionState ... btw, a good trick is to use HttpContext.Current.Session to implement accessors/getters out of the HttpSessionState. Your next challenge would be how to wire it all together.

Roma