I have an MVC app that uses NHibernate for ORM. Each controller takes an ISession construction parameter that is then used to perform CRUD operations on domain model objects. For example,
public class HomeController : Controller
{
public HomeController(ISession session)
{
_session = session;
}
public ViewResult Index(DateTime minDate, DateTime maxDate)
{
var surveys = _session.CreateCriteria<Survey>()
.Add( Expression.Like("Name", "Sm%") )
.Add( Expression.Between("EntryDate", minDate, maxDate) )
.AddOrder( Order.Desc("EntryDate") )
.SetMaxResults(10)
.List<Survey>();
// other logic that I want to unit test that does operations on the surveys variable
return View(someObject);
}
private ISession _session;
}
I would like to unit test this controller in isolation, without actually hitting the database, by mocking the ISession object using Moq or RhinoMocks. However, it is going to be very difficult to mock the ISession interface in the unit test, because it is being used via a fluent interface that chains a number of calls together.
One alternative is to wrap the ISession usage via a repository pattern. I could write a wrapper class something like this:
public interface IRepository
{
List<Survey> SearchSurveyByDate(DateTime minDate, DateTime maxDate);
}
public class SurveyRepository : IRepository
{
public SurveyRepository(ISession session)
{
_session = session;
}
public List<Survey> SearchSurveyByDate(DateTime minDate, DateTime maxDate)
{
return _session.CreateCriteria<Survey>()
.Add( Expression.Like("Name", "Sm%") )
.Add( Expression.Between("EntryDate", minDate, maxDate) )
.AddOrder( Order.Desc("EntryDate") )
.SetMaxResults(10)
.List<Survey>();
}
private ISession _session;
}
I could then re-write my controller to take an IRepository constructor argument, instead of an ISession argument:
public class HomeController : Controller
{
public HomeController(IRepository repository)
{
_repository = repository;
}
public ViewResult Index(DateTime minDate, DateTime maxDate)
{
var surveys = _repository.SearchSurveyByDate(minDate, maxDate);
// other logic that I want to unit test that does operations on the surveys variable
return View(someObject);
}
private IRepository _repository;
}
This second approach would be much easier to unit test, because the IRepository interface would be much easier to mock than the ISession interface, since it is just a single method call. However, I really don't want to go down this route, because:
1) It seems like a really bad idea to create a whole new layer of abstraction and a lot more complexity just to make a unit test easier, and
2) There is a lot of commentary out there that rails against the idea of using a repository pattern with nHibernate, since the ISession interface is already a repository-like interface. (See especially Ayende's posts here and here) and I tend to agree with this commentary.
So my questions is, is there any way I can unit-test my initial implementation by mocking the ISession object? If not, is my only recourse to wrap the ISession query using the repository pattern, or is there some other way I can solve this?